diff options
| author | Rafael H. Schloming <rhs@apache.org> | 2009-12-26 12:42:57 +0000 |
|---|---|---|
| committer | Rafael H. Schloming <rhs@apache.org> | 2009-12-26 12:42:57 +0000 |
| commit | 248f1fe188fe2307b9dcf2c87a83b653eaa1920c (patch) | |
| tree | d5d0959a70218946ff72e107a6c106e32479a398 /cpp/rubygen | |
| parent | 3c83a0e3ec7cf4dc23e83a340b25f5fc1676f937 (diff) | |
| download | qpid-python-248f1fe188fe2307b9dcf2c87a83b653eaa1920c.tar.gz | |
synchronized with trunk except for ruby dir
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/qpid.rnr@893970 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/rubygen')
21 files changed, 839 insertions, 263 deletions
diff --git a/cpp/rubygen/0-10/allsegmenttypes.rb b/cpp/rubygen/0-10/allsegmenttypes.rb index c4c4095e02..26363d6a1f 100755 --- a/cpp/rubygen/0-10/allsegmenttypes.rb +++ b/cpp/rubygen/0-10/allsegmenttypes.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' diff --git a/cpp/rubygen/0-10/exceptions.rb b/cpp/rubygen/0-10/exceptions.rb index 2f62b2ccdf..02e3a5d547 100755 --- a/cpp/rubygen/0-10/exceptions.rb +++ b/cpp/rubygen/0-10/exceptions.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' diff --git a/cpp/rubygen/0-10/handlers.rb b/cpp/rubygen/0-10/handlers.rb index c23eb5faf4..981ea890e6 100755 --- a/cpp/rubygen/0-10/handlers.rb +++ b/cpp/rubygen/0-10/handlers.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' @@ -17,7 +35,7 @@ class GenHandlers < CppGen def generate() h_file("#{@dir}/handlers.h") { - include "specification" + include "#{@dir}/specification" namespace("#{@ns}") { action_handler "Command", @amqp.collect_all(AmqpCommand) action_handler "Control", @amqp.collect_all(AmqpControl) diff --git a/cpp/rubygen/0-10/specification.rb b/cpp/rubygen/0-10/specification.rb index a98292ee4e..7366599eba 100755 --- a/cpp/rubygen/0-10/specification.rb +++ b/cpp/rubygen/0-10/specification.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' @@ -324,8 +342,8 @@ class Specification < CppGen } cpp_file("#{@dir}/#{name}") { - include "#{name}" - include "exceptions.h" + include "#{@dir}/#{name}" + include "#{@dir}/exceptions.h" namespace(@ns) { genl "using framing::in_place;" genl diff --git a/cpp/rubygen/0-10/typecode.rb b/cpp/rubygen/0-10/typecode.rb index e36b92c07c..0ab9c4be5d 100755 --- a/cpp/rubygen/0-10/typecode.rb +++ b/cpp/rubygen/0-10/typecode.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' diff --git a/cpp/rubygen/MethodBodyDefaultVisitor.rb b/cpp/rubygen/MethodBodyDefaultVisitor.rb index 1fff1d51db..4f9b369117 100755 --- a/cpp/rubygen/MethodBodyDefaultVisitor.rb +++ b/cpp/rubygen/MethodBodyDefaultVisitor.rb @@ -1,4 +1,23 @@ #!/usr/bin/env ruby +# +# 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. +# + $: << ".." # Include .. in load path require 'cppgen' diff --git a/cpp/rubygen/amqpgen.rb b/cpp/rubygen/amqpgen.rb index bfa15bb391..69e65a4056 100755 --- a/cpp/rubygen/amqpgen.rb +++ b/cpp/rubygen/amqpgen.rb @@ -1,7 +1,22 @@ +# 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 @@ -15,6 +30,7 @@ require 'delegate' require 'rexml/document' require 'pathname' +require 'set' include REXML # Handy String functions for converting names. @@ -150,7 +166,7 @@ class AmqpElement # The root <amqp> element. def root() @root ||=parent ? parent.root : self; end - def to_s() "#<#{self.class}(#{fqname})>"; end + def to_s() "#<#{self.class}(#{fqname})>"; end def inspect() to_s; end # Text of doc child if there is one. @@ -166,6 +182,21 @@ class AmqpElement 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 @@ -189,14 +220,6 @@ class AmqpEnum < AmqpElement amqp_child_reader :choice 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" -} - class AmqpDomain < AmqpElement def initialize(xml, parent) super @@ -295,7 +318,7 @@ class AmqpFakeMethod < AmqpMethod 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 # FIXME aconway 2008-04-10: ??? + def synchronous() end def on_chassis?(chassis) @action.received_by?(chassis) end @@ -318,7 +341,14 @@ class AmqpAction < AmqpElement def initialize(xml,amqp) super; end amqp_child_reader :implement, :field, :response amqp_attr_reader :code - def implement?(role) xml.elements["./implement[@role='#{role}']"] end + 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 @@ -434,9 +464,12 @@ end # Collect information about generated files. class GenFiles - @@files =[] - def GenFiles.add(f) @@files << f; end + @@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. @@ -446,27 +479,27 @@ 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 - @outdir=outdir + raise "outdir is not an array" unless outdir.class == Array @prefix=[''] # For indentation or comments. @indentstr=' ' # One indent level. @outdent=2 - Pathname.new(@outdir).mkpath unless @outdir=="-" 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 - if (@outdir != "-") - @path=Pathname.new "#{@outdir}/#{file}" + 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 - if block then yield; endfile; end - end - end - - def endfile() - if @outdir != "-" + yield if block if @path.exist? and @path.read == @out puts "Skipped #{@path} - unchanged" # Dont generate if unchanged else diff --git a/cpp/rubygen/cppgen.rb b/cpp/rubygen/cppgen.rb index 3a4228567a..7818e1c4b0 100755 --- a/cpp/rubygen/cppgen.rb +++ b/cpp/rubygen/cppgen.rb @@ -118,6 +118,7 @@ class AmqpRoot # preview; map 0-10 types to preview code generator types @@typemap = { "bit"=> CppType.new("bool").code("Octet").defval("false"), + "boolean"=> CppType.new("bool").code("Octet").defval("false"), "uint8"=>CppType.new("uint8_t").code("Octet").defval("0"), "uint16"=>CppType.new("uint16_t").code("Short").defval("0"), "uint32"=>CppType.new("uint32_t").code("Long").defval("0"), @@ -146,7 +147,7 @@ end class AmqpElement # convert my amqp type_ attribute to a C++ type. def amqp2cpp() - return "ArrayDomain<#{ArrayTypes[name].amqp2cpp}> " if type_=="array" + return "ArrayDomain<#{array_type(name).amqp2cpp}> " if type_=="array" return type_.amqp2cpp end @@ -189,7 +190,7 @@ class AmqpField c=containing_class c.struct(type_) end - def cpptype() lookup_cpptype(type_) or raise "no cpptype #{self}" end + def cpptype() lookup_cpptype(type_) or raise "no cpptype #{type_} for field #{self}" end def cppname() name.lcaps.cppsafe; end def bit?() type_ == "bit"; end def signature() cpptype.param+" "+cppname; end diff --git a/cpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb b/cpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb index f9ef95f5a0..d784e589df 100755 --- a/cpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb +++ b/cpp/rubygen/framing.0-10/MethodBodyConstVisitor.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' diff --git a/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb b/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb index a74b0c06d6..00962de4f9 100755 --- a/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb +++ b/cpp/rubygen/framing.0-10/MethodBodyDefaultVisitor.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' @@ -12,18 +30,19 @@ class MethodBodyDefaultVisitorGen < CppGen def generate() h_file(@filename) { include "qpid/framing/MethodBodyConstVisitor" + include "qpid/CommonImportExport.h" namespace(@namespace) { genl "class AMQMethodBody;" cpp_class(@classname, "public MethodBodyConstVisitor") { genl "public:" genl "virtual void defaultVisit(const AMQMethodBody&) = 0;" @amqp.methods_.each { |m| - genl "virtual void visit(const #{m.body_name}&);" } + genl "QPID_COMMON_EXTERN virtual void visit(const #{m.body_name}&);" } }}} cpp_file(@filename) { include(@filename) - include("all_method_bodies.h") + include("qpid/framing/all_method_bodies.h") namespace(@namespace) { @amqp.methods_.each { |m| genl "void #{@classname}::visit(const #{m.body_name}& b) { defaultVisit(b); }" diff --git a/cpp/rubygen/framing.0-10/MethodBodyFactory.rb b/cpp/rubygen/framing.0-10/MethodBodyFactory.rb new file mode 100644 index 0000000000..95c79fd1a4 --- /dev/null +++ b/cpp/rubygen/framing.0-10/MethodBodyFactory.rb @@ -0,0 +1,58 @@ +#!/usr/bin/env ruby +# +# 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. +# +$: << ".." # Include .. in load path +require 'cppgen' + +class MethodBodyFactoryGen < CppGen + + def initialize(outdir, amqp) + super(outdir, amqp) + @namespace="qpid::framing" + @classname="MethodBodyFactory" + @filename="qpid/framing/MethodBodyFactory" + end + + def generate() + cpp_file(@filename) { + include @filename + include "qpid/framing/BodyFactory" + @amqp.methods_.each { |m| include "qpid/framing/#{m.body_name}" } + include "qpid/Exception.h" + genl + namespace(@namespace) { + scope("boost::intrusive_ptr<AMQMethodBody> #{@classname}::create(ClassId c, MethodId m) {") { + scope("switch (c) {") { + @amqp.classes.each { |c| + scope("case #{c.code}: switch(m) {") { + c.methods_.each { |m| + genl "case #{m.code}: return BodyFactory::create<#{m.body_name}>();" + } + genl "default: throw Exception(QPID_MSG(\"Invalid method id \" << int(m) << \" for class #{c.name} \"));" + } + genl "break;" + } + genl "default: throw Exception(QPID_MSG(\"Invalid class id \" << int(c)));" + } + } + }} + end +end + +MethodBodyFactoryGen.new($outdir, $amqp).generate(); diff --git a/cpp/rubygen/framing.0-10/MethodHolder.rb b/cpp/rubygen/framing.0-10/MethodHolder.rb index 90a9333916..e69de29bb2 100755 --- a/cpp/rubygen/framing.0-10/MethodHolder.rb +++ b/cpp/rubygen/framing.0-10/MethodHolder.rb @@ -1,100 +0,0 @@ -#!/usr/bin/env ruby -$: << ".." # Include .. in load path -require 'cppgen' - -class MethodHolderGen < CppGen - - def initialize(outdir, amqp) - super(outdir, amqp) - @namespace="qpid::framing" - @classname="BodyHolder" - @filename="qpid/framing/BodyHolder" - end - - def gen_max_size() - # Generate program to generate MaxSize.h - cpp_file("generate_MaxMethodBodySize_h") { - include "qpid/framing/AMQHeaderBody" - include "qpid/framing/AMQContentBody" - include "qpid/framing/AMQHeartbeatBody" - @amqp.methods_.each { |m| include "qpid/framing/#{m.body_name}" } - genl - include "<algorithm>" - include "<fstream>" - genl - genl "using namespace std;" - genl "using namespace qpid::framing;" - genl - scope("int main(int, char** argv) {") { - genl "size_t maxSize=0;" - genl "maxSize=max(maxSize, sizeof(AMQHeaderBody));" - genl "maxSize=max(maxSize, sizeof(AMQContentBody));" - genl "maxSize=max(maxSize, sizeof(AMQHeartbeatBody));" - @amqp.methods_.each { |m| - genl "maxSize=max(maxSize, sizeof(#{m.body_name}));" } - gen <<EOS -ofstream out("qpid/framing/MaxMethodBodySize.h"); -out << "// GENERATED CODE: generated by " << argv[0] << endl; -out << "namespace qpid{ namespace framing { " << endl; -out << "const size_t MAX_METHOD_BODY_SIZE=" << maxSize << ";" << endl; -out << "}}" << endl; -EOS - } - } - end - - def gen_construct - cpp_file(@filename+"_gen") { - include @filename - include "qpid/framing/AMQHeaderBody" - include "qpid/framing/AMQContentBody" - include "qpid/framing/AMQHeartbeatBody" - @amqp.methods_.each { |m| include "qpid/framing/#{m.body_name}" } - include "qpid/framing/FrameDefaultVisitor.h" - include "qpid/Exception.h" - genl - namespace(@namespace) { - scope("void #{@classname}::setMethod(ClassId c, MethodId m) {") { - scope("switch (c) {") { - @amqp.classes.each { |c| - scope("case #{c.code}: switch(m) {") { - c.methods_.each { |m| - genl "case #{m.code}: blob = in_place<#{m.body_name}>(); break;" - } - genl "default: throw Exception(QPID_MSG(\"Invalid method id \" << int(m) << \" for class #{c.name} \"));" - } - genl "break;" - } - genl "default: throw Exception(QPID_MSG(\"Invalid class id \" << int(c)));" - } - } - - struct("CopyVisitor", "public FrameDefaultVisitor") { - genl "using FrameDefaultVisitor::visit;" - genl "using FrameDefaultVisitor::defaultVisit;" - genl "BodyHolder& holder;" - genl "CopyVisitor(BodyHolder& h) : holder(h) {}" - ["Header", "Content", "Heartbeat"].each { |type| - genl "void visit(const AMQ#{type}Body& x) { holder=x; }" - } - @amqp.methods_.each { |m| - genl "void visit(const #{m.body_name}& x) { holder=x; }" - } - genl "void defaultVisit(const AMQBody&) { assert(0); }" - } - genl - - scope("void BodyHolder::setBody(const AMQBody& b) {") { - genl "CopyVisitor cv(*this); b.accept(cv);" - } - }} - end - - def generate - gen_max_size - gen_construct - end -end - -MethodHolderGen.new($outdir, $amqp).generate(); - diff --git a/cpp/rubygen/framing.0-10/Operations.rb b/cpp/rubygen/framing.0-10/Operations.rb index 4a67df8b92..cd6a363c56 100755 --- a/cpp/rubygen/framing.0-10/Operations.rb +++ b/cpp/rubygen/framing.0-10/Operations.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# # Usage: output_directory xml_spec_file [xml_spec_file...] # $: << '..' @@ -97,7 +115,7 @@ EOS end end -OperationsGen.new("client",ARGV[0], $amqp).generate() -OperationsGen.new("server",ARGV[0], $amqp).generate() -OperationsGen.new("all",ARGV[0], $amqp).generate() +OperationsGen.new("client",$outdir, $amqp).generate() +OperationsGen.new("server",$outdir, $amqp).generate() +OperationsGen.new("all",$outdir, $amqp).generate() diff --git a/cpp/rubygen/framing.0-10/OperationsInvoker.rb b/cpp/rubygen/framing.0-10/OperationsInvoker.rb index 44006207ca..f9b6cac76b 100755 --- a/cpp/rubygen/framing.0-10/OperationsInvoker.rb +++ b/cpp/rubygen/framing.0-10/OperationsInvoker.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# # Usage: output_directory xml_spec_file [xml_spec_file...] # $: << '..' @@ -56,7 +74,7 @@ class OperationsInvokerGen < CppGen public genl("Invoker(#{target}& target_) : target(target_) {}") genl "using MethodBodyDefaultVisitor::visit;" - methods.each { |m| genl "void visit(const #{m.body_name}& body);" } + methods.each { |m| genl "QPID_COMMON_EXTERN void visit(const #{m.body_name}& body);" } } end @@ -64,6 +82,7 @@ class OperationsInvokerGen < CppGen h_file(@filename) { include "qpid/framing/#{@ops}" include "qpid/framing/Invoker.h" + include "qpid/CommonImportExport.h" namespace("qpid::framing") { # AMQP_*Operations invoker. methods=@amqp.classes.map { |c| visit_methods(c).to_a }.flatten @@ -93,6 +112,6 @@ class OperationsInvokerGen < CppGen end end -OperationsInvokerGen.new("client",ARGV[0], $amqp).generate() -OperationsInvokerGen.new("server",ARGV[0], $amqp).generate() -OperationsInvokerGen.new("all",ARGV[0], $amqp).generate() +OperationsInvokerGen.new("client",$outdir, $amqp).generate() +OperationsInvokerGen.new("server",$outdir, $amqp).generate() +OperationsInvokerGen.new("all",$outdir, $amqp).generate() diff --git a/cpp/rubygen/framing.0-10/Proxy.rb b/cpp/rubygen/framing.0-10/Proxy.rb index 71a6b954c6..6e3cb4fd4d 100755 --- a/cpp/rubygen/framing.0-10/Proxy.rb +++ b/cpp/rubygen/framing.0-10/Proxy.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' @@ -19,14 +37,14 @@ class ProxyGen < CppGen def inner_class_decl(c) cname=c.name.caps - cpp_class(cname, "Proxy") { + cpp_class(cname, "public Proxy") { gen <<EOS public: #{cname}(FrameHandler& f) : Proxy(f) {} static #{cname}& get(#{@classname}& proxy) { return proxy.get#{cname}(); } EOS methods_on(c, @chassis).each { |m| - genl "virtual void #{m.cppname}(#{m.signature.join(",\n ")});" + genl "QPID_COMMON_EXTERN virtual void #{m.cppname}(#{m.signature.join(",\n ")});" genl }} end @@ -48,10 +66,12 @@ EOS include "qpid/framing/Array.h" include "qpid/framing/amqp_types.h" include "qpid/framing/amqp_structs.h" + include "qpid/CommonImportExport.h" + namespace("qpid::framing") { cpp_class(@classname, "public Proxy") { public - genl "#{@classname}(FrameHandler& out);" + genl "QPID_COMMON_EXTERN #{@classname}(FrameHandler& out);" genl @amqp.classes.each { |c| inner_class_decl(c) @@ -66,7 +86,7 @@ EOS # .cpp file cpp_file(@filename) { include "<sstream>" - include "#{@classname}.h" + include "qpid/framing/#{@classname}.h" include "qpid/framing/amqp_types_full.h" methods_on(@amqp, @chassis).each { |m| include "qpid/framing/"+m.body_name @@ -74,7 +94,7 @@ EOS genl namespace("qpid::framing") { genl "#{@classname}::#{@classname}(FrameHandler& f) :" - gen " Proxy(f)" + gen " Proxy(f)" @amqp.classes.each { |c| gen ",\n "+proxy_member(c)+"(f)" } genl "{}\n" @amqp.classes.each { |c| inner_class_defn(c) } diff --git a/cpp/rubygen/framing.0-10/Session.rb b/cpp/rubygen/framing.0-10/Session.rb index 9f54ad1675..61f0e03a8b 100644..100755 --- a/cpp/rubygen/framing.0-10/Session.rb +++ b/cpp/rubygen/framing.0-10/Session.rb @@ -1,17 +1,38 @@ #!/usr/bin/env ruby +# +# 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. +# # Usage: output_directory xml_spec_file [xml_spec_file...] # $: << '..' require 'cppgen' class CppGen - def session_methods + def session_methods(sync_default) excludes = ["connection", "session", "file", "stream"] gen_methods=@amqp.methods_on(@chassis).reject { |m| excludes.include? m.parent.name or m.body_name.include?("010") } + gen_methods.each { |m| m.set_sync_default(sync_default) } end + + # Generates a doxygen comment for AmqpMethod m. def doxygen(m) doxygen_comment { genl m.doc @@ -34,9 +55,9 @@ module SyncAsync def decl_ctor_opeq() genl - genl "#{@classname}();" - genl "#{@classname}(const #{@version_base}& other);" - genl "#{@classname}& operator=(const #{@version_base}& other);" + genl "QPID_CLIENT_EXTERN #{@classname}();" + genl "QPID_CLIENT_EXTERN #{@classname}(const #{@version_base}& other);" + genl "QPID_CLIENT_EXTERN #{@classname}& operator=(const #{@version_base}& other);" end def defn_ctor_opeq(inline="") @@ -50,23 +71,35 @@ module SyncAsync genl "return *this;" } end + + def sync_default() !@async end end class ContentField # For extra content parameters def cppname() "content" end - def signature() "const MethodContent& content" end - def sig_default() signature+"="+"DefaultContent(std::string())" end - def unpack() "p[arg::content|DefaultContent(std::string())]"; end + def signature() "const Message& content" end + def sig_default() signature+"="+"Message(std::string())" end + def unpack() "p[arg::content|Message(std::string())]"; end def doc() "Message content"; end end +class SyncField # For extra sync parameters + def initialize(default_value) @default_value=default_value ? "true" : "false" end + def cppname() "sync" end + def signature() "bool sync" end + def sig_default() signature+"="+@default_value end + def unpack() "p[arg::sync|#{@default_value}]"; end + def doc() "If true the broker will respond with completion status as soon as possible."; end +end + class AmqpField def unpack() "p[arg::#{cppname}|#{default_value}]"; end def sig_default() signature+"="+default_value; end end class AmqpMethod - def fields_c() content ? fields+[ContentField.new] : fields end + def set_sync_default(sync_default) @sync_default=sync_default end + def fields_c() result = fields + (content ? [ContentField.new] : []) + [SyncField.new(@sync_default)] end def param_names_c() fields_c.map { |f| f.cppname} end def signature_c() fields_c.map { |f| f.signature }; end def sig_c_default() fields_c.map { |f| f.sig_default }; end @@ -103,8 +136,10 @@ class SessionNoKeywordGen < CppGen end def generate() + public_api("#{@file}.h") h_file(@file) { include "qpid/client/#{@version_base}.h" + include "qpid/client/ClientImportExport.h" namespace(@namespace) { doxygen_comment { genl "AMQP #{@amqp.version} #{sync_adjective} session API." @@ -114,31 +149,36 @@ class SessionNoKeywordGen < CppGen cpp_class(@classname, "public #{@version_base}") { public decl_ctor_opeq() - session_methods.each { |m| + session_methods(sync_default).each { |m| genl doxygen(m) args=m.sig_c_default.join(", ") - genl "#{m.return_type(@async)} #{m.session_function}(#{args});" + genl "QPID_CLIENT_EXTERN #{m.return_type(@async)} #{m.session_function}(#{args});" } } }} cpp_file(@file) { - include @classname + include "qpid/client/#{@classname}" include "qpid/framing/all_method_bodies.h" + include "qpid/client/SessionImpl.h" + include "qpid/client/MessageImpl.h" + include "qpid/client/PrivateImplRef.h" + include "qpid/client/CompletionImpl.h" + include "<boost/intrusive_ptr.hpp>" namespace(@namespace) { genl "using namespace framing;" - session_methods.each { |m| + session_methods(sync_default).each { |m| genl sig=m.signature_c.join(", ") func="#{@classname}::#{m.session_function}" scope("#{m.return_type(@async)} #{func}(#{sig}) {") { args=(["ProtocolVersion(#{@amqp.major},#{@amqp.minor})"]+m.param_names).join(", ") genl "#{m.body_name} body(#{args});"; - genl "body.setSync(#{@async ? 'false':'true'});" + genl "body.setSync(sync);" sendargs="body" - sendargs << ", content" if m.content - async_retval="#{m.return_type(true)}(impl->send(#{sendargs}), impl)" + sendargs << ", *MessageImpl::get(content)" if m.content + async_retval="#{m.return_type(true)}(new CompletionImpl(impl->send(#{sendargs}), impl))" if @async then genl "return #{async_retval};" else @@ -180,9 +220,10 @@ class SessionGen < CppGen end def generate() - keyword_methods=session_methods.reject { |m| m.fields_c.empty? } + keyword_methods=session_methods(sync_default).reject { |m| m.fields_c.empty? } max_arity = keyword_methods.map{ |m| m.fields_c.size }.max + public_api("qpid/client/arg.h") h_file("qpid/client/arg.h") { # Generate keyword tag declarations. genl "#define BOOST_PARAMETER_MAX_ARITY #{max_arity}" @@ -192,10 +233,11 @@ class SessionGen < CppGen genl "BOOST_PARAMETER_KEYWORD(keyword_tags, #{k})" }} } - + public_api("#{@fqclass.file}.h") h_file(@fqclass.file) { include @fqbase.file include "qpid/client/arg" + include "qpid/client/ClientImportExport" namespace("qpid::client") { # Doxygen comment. doxygen_comment { @@ -219,6 +261,136 @@ which provides the same set of functions using normal non-keyword declarations. \\ingroup clientapi + + +\\details + +<h2>Publishing Messages</h2> +<ul> +<li><p>messageTransfer()</p> +<pre>session.messageTransfer(arg::content=message, arg::destination="amq.topic");</pre></li> +<li><p>messageTransfer() — asynchronous</p> +<pre>#include <qpid/client/AsyncSession.h> + +for (int i=0; i<10; i++) { + message.setData(message_data.str()); + async(session).messageTransfer(arg::content=message, arg::destination="amq.direct"); +} + +session.sync(); +</pre> +</li> +</ul> + +<h2>Exchanges</h2> +<ul> +<li><p>exchangeBind()</p> +<pre>session.exchangeBind(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey=routing_key);</pre> +</li> +<li><p>exchangeUnbind()</p> +<pre>session.exchangeUnBind(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey=routing_key);</pre></li> +<li><p>exchangeBound()</p> +<pre>if (session.exchangeBound(arg::exchange="amq.topic", arg::queue=queue, arg::bindingKey=rk)){...}</pre> +<pre>if (session.exchangeBound(arg::exchange="amq.topic", arg::queue=queue)){...}</pre> +</li> +<li><p>exchangeDeclare()</p> +<pre>session.exchangeDeclare(arg::exchange="my.topic", arg::type="topic");</pre> +<pre>session.exchangeDeclare(arg::exchange="xml", arg::type="xml");</pre> +</li> +<li><p>exchangeDelete()</p> +<pre>session.exchangeDeclare(arg::exchange="my.topic");</pre> +<pre>session.exchangeDeclare(arg::exchange="xml", arg::ifUnused=true);</pre> +</li> +<li><p>exchangeQuery()</p> +<pre>ExchangeQueryResult eqr = session.exchangeQuery(arg::exchange="my.topic");</pre></li> +</ul> + + +<h2>Configuring exchanges in session.exchangeDeclare</h2> + +<pre>arg::durable=true</pre> +<p>Default: false.</p> +<p>If durable=true, an exchange remains active even if the server is restarted. If durable=false, an exchange is purged when a server restarts.</p> + +<pre>arg::autoDelete=true</pre> +<p>Default: false.</p> +<p>If autoDelete=true, deleting the last binding for an exchange also deletes the exchange.</p> + +<pre>arg::alternatExchange="my.exchange"</pre> +<p>Default: none.</p> +<p>If an alternate exchange is specified, messages that can not be delivered to any queue are sent to the alternate exchange.</p> + +<h2>Queues</h2> +<ul> +<li><p>queueDeclare()</p> +<pre>session.queueDeclare(arg::queue="message_queue");</pre> +</li> +<li><p>queueDelete()</p> +<pre>session.queueDelete(arg::queue="message_queue");</pre></li> +<li><p>queuePurge()</p> +<pre>session.queuePurge(arg::queue="message_queue");</pre></li> +<li><p>queueQuery()</p> +<pre>QueueQueryResult qqr = session.queueQuery(arg::queue="message_queue");</pre></li> +</ul> + + +<h2>Configuring queues with session.queueDeclare</h2> +<pre>arg::durable=true</pre> +<p>Default: false.</p> +<p>If durable=true, a queue remains active if the server is restarted. If durable=false, a queue and its contents are lost when a server restarts.</p> +<br/> + +<pre>arg::autoDelete=true</pre> +<p>Default: false.</p> +<p>If autoDelete=true, the queue is deleted when the last active Subscription to the Queue is canceled.</p> +<br/> + +<pre>arg::exclusive=true</pre> +<p>Default: false.</p> +<p>If exclusive=true, only the Session that created a queue can access it.</p> +<br/> + +<pre>arg::alternateExchange="my.exchange"</pre> +<p>Default: none. </p> +<p>If an alternate exchange is specified, messages are routed to it if (1) they are rejected by a client, or (2) they remain on the queue when it is deleted.</p> +<br/> + + +<h2>Accepting, Acquiring, Rejecting, or Releasing Messages</h2> +<ul> +<li><p>messageAccept() — acknowledges messages</p> +<pre>SequenceSet tobeAccepted; +toAccepted.add(msg.getId()); +session.messageAccept(toBeAccepted);</pre> +</li> +<li><p>messageAcquire()</p> +<pre>SequenceSet tobeAcquired; +toBeAcquired.add(msg.getId()); +session.messageAcquire(toBeAcquired);</pre> +</li> +<li><p>messageReject()</p> +<pre>SequenceSet tobeRejected; +toRejected.add(msg.getId()); +session.messageReject(toBeRejected);</pre> +</li> +<li><p>messageRelease()</p> +<pre>SequenceSet tobeReleased; +toReleased.add(msg.getId()); +session.messageRelease(toBeReleased);</pre></li> +</ul> + +<h2>Transactions</h2> +<ul> +<li><p>txSelect()</p> +<pre>session.txSelect();</pre> +</li> +<li><p>txCommit()</p> +<pre>session.txSelect();</pre></li> +<li><p>txRollback()</p> +<pre>session.txRollback();</pre></li> +</ul> + + EOS } # Session class. @@ -238,8 +410,8 @@ EOS end end -SessionNoKeywordGen.new(ARGV[0], $amqp, true).generate() -SessionNoKeywordGen.new(ARGV[0], $amqp, false).generate() -SessionGen.new(ARGV[0], $amqp, true).generate() -SessionGen.new(ARGV[0], $amqp, false).generate() +SessionNoKeywordGen.new($outdir, $amqp, true).generate() +SessionNoKeywordGen.new($outdir, $amqp, false).generate() +SessionGen.new($outdir, $amqp, true).generate() +SessionGen.new($outdir, $amqp, false).generate() diff --git a/cpp/rubygen/framing.0-10/all_method_bodies.rb b/cpp/rubygen/framing.0-10/all_method_bodies.rb index 5971d49189..4c7fccfff5 100755 --- a/cpp/rubygen/framing.0-10/all_method_bodies.rb +++ b/cpp/rubygen/framing.0-10/all_method_bodies.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' diff --git a/cpp/rubygen/framing.0-10/constants.rb b/cpp/rubygen/framing.0-10/constants.rb index 7f026a3e54..5c1c1047f7 100755 --- a/cpp/rubygen/framing.0-10/constants.rb +++ b/cpp/rubygen/framing.0-10/constants.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' @@ -11,8 +29,10 @@ class ConstantsGen < CppGen end def constants_h() - h_file("#{@dir}/constants") { - namespace(@namespace) { + public_api("#{@dir}/constants.h") + h_file("#{@dir}/constants.h") { + namespace(@namespace) { + # Constants for class/method names. scope("enum AmqpConstant {","};") { l=[] l.concat @amqp.constants.map { |c| "#{c.name.shout}=#{c.value}" } @@ -23,53 +43,137 @@ class ConstantsGen < CppGen } genl l.join(",\n") } - define_constants_for(@amqp.domain("segment-type").enum) - namespace("execution") { - define_constants_for(@amqp.class_("execution").domain("error-code").enum) + } + } + end + + def typecode_enum(t) "TYPE_CODE_#{t.name.shout}" end + + def typecode_h_cpp + path="#{@dir}/TypeCode" + public_api(path+".h") + h_file(path) { + include("<iosfwd>") + include("\"qpid/sys/IntegerTypes.h\"") + namespace(@namespace) { + scope("enum TypeCode {", "};") { + genl @amqp.types.map { |t| "#{typecode_enum t} = #{t.code}" if t.code }.compact.join(",\n") } - namespace("connection") { - define_constants_for(@amqp.class_("connection").domain("close-code").enum) + genl <<EOS + +/** True if t is a valid TypeCode value */ +bool isTypeCode(uint8_t t); + +/** Throw exception if not a valid TypeCode */ +TypeCode typeCode(uint8_t); + +/**@return 0 if t is not a valid enum TypeCode value. */ +const char* typeName(TypeCode t); + +std::ostream& operator<<(std::ostream&, TypeCode); +EOS + } + } + + cpp_file(path) { + include(path); + include("qpid/Exception.h") + include("<ostream>") + namespace(@namespace) { + scope("const char* typeName(TypeCode t) {") { + scope("switch (t) {") { + @amqp.types.each { |t| genl "case #{typecode_enum t}: return \"#{t.name}\";" if t.code } + genl "default: break;" + } + genl "return 0;"; } - namespace("session") { - define_constants_for(@amqp.class_("session").domain("detach-code").enum) + genl <<EOS + +bool isTypeCode(uint8_t t) { return typeName(TypeCode(t)); } + +TypeCode typeCode(uint8_t t) { + if (!isTypeCode(t)) throw Exception(QPID_MSG("Invalid TypeCode " << t)); + return TypeCode(t); +} + +std::ostream& operator<<(std::ostream& o, TypeCode t) { + if (isTypeCode(t)) return o << typeName(t); + else return o << "Invalid TypeCode " << t; +} +EOS + } + } + end + + def enum_h() + public_api("#{@dir}/enum.h") + h_file("#{@dir}/enum.h") { + # Constants for enum domains. + namespace(@namespace) { + @amqp.domains.each { |d| declare_enum(d.enum) if d.enum } + @amqp.classes.each { |c| + enums=c.collect_all(AmqpEnum) + if !enums.empty? then + namespace(c.nsname) { enums.each { |e| declare_enum(e) } } + end } - define_constants_for(@amqp.class_("dtx").domain("xa-status").enum) } } end - def define_constants_for(enum) - scope("enum #{enum.parent.name.caps} {","};") { - genl enum.choices.collect { |c| "#{c.name.shout}=#{c.value}" }.join(",\n") + def declare_enum(enum) + # Generated like this: enum containing_class::Foo { FOO_X, FOO_Y; } + name="#{enum.parent.name.caps}" + prefix=enum.parent.name.shout+"_" + scope("enum #{name} {","};") { + genl enum.choices.collect { |c| "#{prefix}#{c.name.shout}=#{c.value}" }.join(",\n") } end - def define_exception(c, base, package) - name=c.name.caps+"Exception" - genl - doxygen_comment { genl c.doc } - struct(c.name.caps+"Exception", base) { + def declare_exception(c, base, package, enum) + name=c.name.caps+"Exception" + value="#{package}::#{enum.parent.name.shout}_#{c.name.shout}" + genl + doxygen_comment { genl c.doc } + struct(c.name.caps+"Exception", base) { genl "std::string getPrefix() const { return \"#{c.name}\"; }" - genl "#{c.name.caps}Exception(const std::string& msg=std::string()) : #{base}(#{c.value}, \"\"+msg) {}" - } + genl "#{c.name.caps}Exception(const std::string& msg=std::string()) : #{base}(#{value}, \"\"+msg) {}" + } end - def define_exceptions_for(class_name, domain_name, base) + def declare_exceptions(class_name, domain_name, base) enum = @amqp.class_(class_name).domain(domain_name).enum - enum.choices.each { |c| define_exception(c, base, class_name) unless c.name == "normal" } + enum.choices.each { |c| declare_exception(c, base, class_name, enum) unless c.name == "normal" } + genl + genl "QPID_COMMON_EXTERN sys::ExceptionHolder create#{base}(int code, const std::string& text);" + end + + def create_exception(class_name, domain_name, base, invalid) + scope("sys::ExceptionHolder create#{base}(int code, const std::string& text) {") { + genl "sys::ExceptionHolder holder;" + scope("switch (code) {") { + enum = @amqp.class_(class_name).domain(domain_name).enum + enum.choices.each { |c| + assign = "holder = new #{c.name.caps}Exception(text); " unless c.name == "normal" + genl "case #{c.value}: #{assign}break;" + } + genl "default: holder = new #{invalid}(QPID_MSG(\"Bad #{enum.parent.name}: \" << code << \": \" << text));" + } + genl "return holder;" + } end def reply_exceptions_h() - h_file("#{@dir}/reply_exceptions") { + public_api("#{@dir}/reply_exceptions.h") + h_file("#{@dir}/reply_exceptions.h") { include "qpid/Exception" include "qpid/sys/ExceptionHolder" + include "qpid/framing/enum" + include "qpid/CommonImportExport.h" namespace(@namespace) { - define_exceptions_for("execution", "error-code", "SessionException") - define_exceptions_for("connection", "close-code", "ConnectionException") - define_exceptions_for("session", "detach-code", "ChannelException") - genl - genl "void throwExecutionException(int code, const std::string& text);" - genl "void setExecutionException(sys::ExceptionHolder& holder, int code, const std::string& text);" + declare_exceptions("execution", "error-code", "SessionException") + declare_exceptions("connection", "close-code", "ConnectionException") + declare_exceptions("session", "detach-code", "ChannelException") } } end @@ -80,29 +184,21 @@ class ConstantsGen < CppGen include "<sstream>" include "<assert.h>" namespace("qpid::framing") { - scope("void throwExecutionException(int code, const std::string& text) {"){ - genl "sys::ExceptionHolder h;" - genl "setExecutionException(h, code, text);" - genl "h.raise();" - } - scope("void setExecutionException(sys::ExceptionHolder& holder, int code, const std::string& text) {"){ - scope("switch (code) {") { - enum = @amqp.class_("execution").domain("error-code").enum - enum.choices.each { |c| - genl "case #{c.value}: holder = new #{c.name.caps}Exception(text); break;" - } - genl 'default: assert(0);' - genl ' holder = new InvalidArgumentException(QPID_MSG("Bad exception code: " << code << ": " << text));' - } - } + create_exception("execution", "error-code", "SessionException", "InvalidArgumentException") + # FIXME aconway 2008-10-07: there are no good exception codes in 0-10 for an invalid code. + # The following choices are arbitrary. + create_exception("connection", "close-code", "ConnectionException", "FramingErrorException") + create_exception("session", "detach-code", "ChannelException", "NotAttachedException") } } end def generate() constants_h + enum_h reply_exceptions_h reply_exceptions_cpp + typecode_h_cpp end end diff --git a/cpp/rubygen/framing.0-10/frame_body_lists.rb b/cpp/rubygen/framing.0-10/frame_body_lists.rb index b20e4550f3..4f1b976032 100644 --- a/cpp/rubygen/framing.0-10/frame_body_lists.rb +++ b/cpp/rubygen/framing.0-10/frame_body_lists.rb @@ -1,3 +1,21 @@ +# +# 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. +# $: << ".." # Include .. in load path require 'cppgen' @@ -26,6 +44,6 @@ EOS end end -FrameBodyListsGen.new(ARGV[0], $amqp).generate; +FrameBodyListsGen.new($outdir, $amqp).generate; diff --git a/cpp/rubygen/framing.0-10/structs.rb b/cpp/rubygen/framing.0-10/structs.rb index e4d57ca75d..c3684aea66 100644..100755 --- a/cpp/rubygen/framing.0-10/structs.rb +++ b/cpp/rubygen/framing.0-10/structs.rb @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# # Usage: output_directory xml_spec_file [xml_spec_file...] # $: << '..' @@ -26,6 +44,12 @@ class StructGen < CppGen "timestamp"=>8 } + StringSizeMap={ + "LongString"=>4, + "MediumString"=>2, + "ShortString"=>1 + } + SizeType={ 1=>"Octet", 2=>"Short", @@ -153,13 +177,10 @@ class StructGen < CppGen genl "total += #{size};//#{f.cppname}" elsif (f.cpptype.name == "SequenceNumberSet") genl "total += #{f.cppname}.encodedSize();" - else - encoded = f.cpptype.encoded - gen "total += (" - gen "4 + " if encoded == "LongString" - gen "2 + " if encoded == "MediumString" - gen "1 + " if encoded == "ShortString" - genl "#{f.cppname}.size());" + elsif (size = StringSizeMap[f.cpptype.encoded]) + genl "total += #{size} + #{f.cppname}.size();" + else + genl "total += #{f.cppname}.encodedSize();" end end end @@ -212,6 +233,7 @@ class StructGen < CppGen using AMQMethodBody::accept; void accept(MethodBodyConstVisitor& v) const { v.visit(*this); } + boost::intrusive_ptr<AMQBody> clone() const { return BodyFactory::copy(*this); } ClassId amqpClassId() const { return CLASS_ID; } MethodId amqpMethodId() const { return METHOD_ID; } @@ -329,15 +351,15 @@ EOS end def declare_packed_accessors(f) - genl "void set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname});"; - genl "#{f.cpptype.ret} get#{f.name.caps}() const;" + genl "QPID_COMMON_EXTERN void set#{f.name.caps}(#{f.cpptype.param} _#{f.cppname});"; + genl "QPID_COMMON_EXTERN #{f.cpptype.ret} get#{f.name.caps}() const;" if (f.cpptype.name == "FieldTable") - genl "#{f.cpptype.name}& get#{f.name.caps}();" + genl "QPID_COMMON_EXTERN #{f.cpptype.name}& get#{f.name.caps}();" end if (f.type_ != "bit") #extra 'accessors' for packed fields: - genl "bool has#{f.name.caps}() const;" - genl "void clear#{f.name.caps}Flag();" + genl "QPID_COMMON_EXTERN bool has#{f.name.caps}() const;" + genl "QPID_COMMON_EXTERN void clear#{f.name.caps}Flag();" end end @@ -359,9 +381,11 @@ EOS else inheritance = ": public AMQMethodBody" end + else + public_api("qpid/framing/#{classname}.h") # Non-method structs are public end - h_file("qpid/framing/#{classname}.h") { + h_file("qpid/framing/#{classname}.h") { if (s.kind_of? AmqpMethod) gen <<EOS #include "qpid/framing/AMQMethodBody.h" @@ -377,6 +401,7 @@ EOS #include <ostream> #include "qpid/framing/amqp_types_full.h" +#include "qpid/CommonImportExport.h" namespace qpid { namespace framing { @@ -416,17 +441,17 @@ EOS methodbody_extra_defs(s) end if (s.kind_of? AmqpStruct) - indent {genl "friend std::ostream& operator<<(std::ostream&, const #{classname}&);" } + indent {genl "QPID_COMMON_EXTERN friend std::ostream& operator<<(std::ostream&, const #{classname}&);" } end gen <<EOS - void encode(Buffer&) const; - void decode(Buffer&, uint32_t=0); - void encodeStructBody(Buffer&) const; - void decodeStructBody(Buffer&, uint32_t=0); - uint32_t size() const; - uint32_t bodySize() const; - void print(std::ostream& out) const; + QPID_COMMON_EXTERN void encode(Buffer&) const; + QPID_COMMON_EXTERN void decode(Buffer&, uint32_t=0); + QPID_COMMON_EXTERN void encodeStructBody(Buffer&) const; + QPID_COMMON_EXTERN void decodeStructBody(Buffer&, uint32_t=0); + QPID_COMMON_EXTERN uint32_t encodedSize() const; + QPID_COMMON_EXTERN uint32_t bodySize() const; + QPID_COMMON_EXTERN void print(std::ostream& out) const; }; /* class #{classname} */ }} @@ -439,9 +464,8 @@ EOS buffer = "/*buffer*/" end gen <<EOS -#include "#{classname}.h" - -#include "reply_exceptions.h" +#include "qpid/framing/#{classname}.h" +#include "qpid/framing/reply_exceptions.h" using namespace qpid::framing; @@ -528,8 +552,7 @@ EOS return total; } -uint32_t #{classname}::size() const -{ +uint32_t #{classname}::encodedSize() const { uint32_t total = bodySize(); EOS if (s.kind_of? AmqpStruct) @@ -583,9 +606,10 @@ EOS structs.each { |s| define_struct(s) } @amqp.methods_.each { |m| define_struct(m) } #generate a single include file containing the list of structs for convenience - h_file("qpid/framing/amqp_structs.h") { structs.each { |s| genl "#include \"#{s.cppname}.h\"" } } + public_api("qpid/framing/amqp_structs.h") + h_file("qpid/framing/amqp_structs.h") { structs.each { |s| genl "#include \"qpid/framing/#{s.cppname}.h\"" } } end end -StructGen.new(ARGV[0], $amqp).generate() +StructGen.new($outdir, $amqp).generate() diff --git a/cpp/rubygen/generate b/cpp/rubygen/generate index 9acbd4fe83..89b9b99520 100755 --- a/cpp/rubygen/generate +++ b/cpp/rubygen/generate @@ -1,4 +1,22 @@ #!/usr/bin/env ruby +# +# 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. +# require 'pathname' require 'amqpgen' @@ -7,14 +25,14 @@ require 'amqpgen' # if ARGV.size < 3 puts <<EOS -Usage: #{ARGV[0]} OUTDIR SPEC.xml [ ... ] TEMPLATE.rb [ ... ] -or: #{ARGV[0]} OUTDIR SPEC.xml [ ... ] all [ makefragment.mk ] +Usage: #{ARGV[0]} SRCDIR APIDIR SPEC.xml [ ... ] TEMPLATE.rb [ ... ] +or: #{ARGV[0]} SRCDIR APIDIR SPEC.xml [ ... ] all [ makefragment.mk | makefragment.cmake ] Parse all SPEC.xml files to create an AMQP model, run each TEMPLATE -putting the resulting files under OUTDIR. Prints a list of files -generated to standard output. +putting the resulting files under SRCDIR, public API files in APIdir. +Prints a list of files generated to standard output. -If OUTDIR is '-' then just prints file list without generating files. +If SRCDIR and APIDIR are '-' then just prints file list without generating files. EOS exit 1 end @@ -39,15 +57,16 @@ gendir=File.dirname(__FILE__) if ARGV.any? { |arg| arg=="all" } templates=Dir["#{gendir}/*/*.rb"] else - templates=ARGV.grep(/\.rb$/) +templates=ARGV.grep(/\.rb$/) ARGV.each { |arg| d=File.join gendir,arg templates += Dir["#{d}/*.rb"] if File.directory? d } end -$outdir=ARGV[0] +$outdir=[ ARGV[0], ARGV[1] ] $models=parse_specs(ARGV.grep(/\.xml$/)) + templates.each { |t| ver=Pathname.new(t).dirname.basename.to_s.split('.')[-1] $amqp=$models[ver] @@ -58,50 +77,84 @@ templates.each { |t| end } +def cmake_continue(lines) lines.join(" \n "); end def make_continue(lines) lines.join(" \\\n "); end # Generate makefile makefile=ARGV.grep(/.mk$/)[0] -if makefile +cmakefile=ARGV.grep(/.cmake$/)[0] +if cmakefile || makefile + srcdir,apidir=$outdir dir=Dir.getwd Dir.chdir File.dirname(__FILE__) generator_files=Dir["**/*.rb"] << File.basename(__FILE__) Dir.chdir dir rgen_generator=generator_files.map{ |f| "$(rgen_dir)/#{f}" } - rgen_srcs=GenFiles.get.map{ |f| "#{$outdir}/#{f}" } + cmake_rgen_generator=generator_files.map{ |f| "${rgen_dir}/#{f}" } + rgen_srcs=GenFiles.get.map{ |f| "#{GenFiles.public_api?(f) ? apidir : srcdir}/#{f}" } rgen_subdirs={} rgen_srcs.each { |src| - if src.match(%r{#{$outdir}/qpid/([^/]+)/}) - subdir=$1 + if src.match(%r{(#{srcdir}|#{apidir})/qpid/([^/]+)/}) + subdir=$2 rgen_subdirs[subdir] ||= [] rgen_subdirs[subdir] << src end } - File.open(makefile, 'w') { |out| - out << <<EOS + if (makefile) + File.open(makefile, 'w') { |out| + out << <<EOS # Generated makefile fragment. # Including makefile defines $(rgen_dir) $(rgen_cmd) and $(specs). rgen_generator=#{make_continue rgen_generator} EOS - rgen_subdirs.each_key { |subdir| - out << "\nrgen_#{subdir}_srcs = #{make_continue(rgen_subdirs[subdir])}\n" - } - out << <<EOS + rgen_subdirs.each_key { |subdir| + out << "\nrgen_#{subdir}_srcs = #{make_continue(rgen_subdirs[subdir])}\n" + } + out << <<EOS rgen_srcs=#{make_continue rgen_srcs} # Header file install rules. EOS - ["amqp_0_10", "framing", "client/no_keyword","client", "broker"].each { |ns| - dir="qpid/#{ns}" - dir_ = dir.tr("/", "_") - regex=%r|#{dir}/[^/]+\.h$| - out << <<EOS + ["amqp_0_10", "framing", "client/no_keyword","client", "broker"].each { |ns| + dir="qpid/#{ns}" + dir_ = dir.tr("/", "_") + regex=%r|#{dir}/[^/]+\.h$| + out << <<EOS #{dir_}dir = $(includedir)/#{dir} dist_#{dir_}_HEADERS = #{make_continue rgen_srcs.grep(regex)} EOS - } - } -end + } # each + } # File makefile + end # if (makefile) + if (cmakefile) + File.open(cmakefile, 'w') { |out| + out << <<EOS +# Generated makefile fragment. +# Including makefile defines ${rgen_dir} ${rgen_cmd} and ${specs}. + +set(rgen_generator #{cmake_continue cmake_rgen_generator}) +EOS + rgen_subdirs.each_key { |subdir| + out << "\nset(rgen_#{subdir}_srcs #{cmake_continue(rgen_subdirs[subdir])})\n" + } + out << <<EOS +set(rgen_srcs #{cmake_continue rgen_srcs}) + +# Header file install rules. +EOS + ["amqp_0_10", "framing", "client/no_keyword","client", "broker"].each { |ns| + dir="qpid/#{ns}" + dir_ = dir.tr("/", "_") + regex=%r|#{dir}/[^/]+\.h$| + out << <<EOS +set(#{dir_}dir \${includedir}/#{dir}) +set(dist_#{dir_}_HEADERS #{cmake_continue rgen_srcs.grep(regex)}) + +EOS + } # each + } # File makefile + end # if (makefile) +end |
