Author: aconway
Date: Thu Apr 10 05:36:58 2008
New Revision: 646778

URL: http://svn.apache.org/viewvc?rev=646778&view=rev
Log:
Invocation handlers, see src/tests/amqp_0_10/handlers.cpp for example.

Added:
    incubator/qpid/trunk/qpid/cpp/rubygen/0-10/handlers.rb   (with props)
    incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/handlers.cpp   (with 
props)
Modified:
    incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb
    incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Holder.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Unit.h
    incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am

Added: incubator/qpid/trunk/qpid/cpp/rubygen/0-10/handlers.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/0-10/handlers.rb?rev=646778&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/0-10/handlers.rb (added)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/0-10/handlers.rb Thu Apr 10 05:36:58 
2008
@@ -0,0 +1,29 @@
+#!/usr/bin/env ruby
+$: << ".."                      # Include .. in load path
+require 'cppgen'
+
+class GenHandlers < CppGen
+  def initialize(outdir, amqp)
+    super(outdir, amqp)
+    @ns="qpid::[EMAIL PROTECTED]"
+    @dir="qpid/[EMAIL PROTECTED]"
+  end
+
+  def action_handler(type, actions)
+    genl
+    bases=actions.map { |a| "public #{a.fqclassname}::Handler" }
+    struct("#{type}Handler", *bases) { }
+  end
+
+  def generate()
+    h_file("[EMAIL PROTECTED]/handlers.h") {
+      include "specification"
+      namespace("[EMAIL PROTECTED]") { 
+        action_handler "Command", @amqp.collect_all(AmqpCommand)
+        action_handler "Control", @amqp.collect_all(AmqpControl)
+      }
+    }
+  end
+end
+
+GenHandlers.new($outdir, $amqp).generate()

Propchange: incubator/qpid/trunk/qpid/cpp/rubygen/0-10/handlers.rb
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/rubygen/0-10/handlers.rb
------------------------------------------------------------------------------
    svn:executable = *

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb?rev=646778&r1=646777&r2=646778&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/0-10/specification.rb Thu Apr 10 
05:36:58 2008
@@ -69,7 +69,7 @@
     genl "bool operator==(const #{x.classname}&, const #{x.classname}&);"
   end
 
-  def action_struct_cpp(x)
+  def action_struct_cpp(x, &block)
     genl
     genl "const char* #{x.classname}::NAME=\"#{x.fqname}\";"
     genl "const char* 
#{x.classname}::CLASS_NAME=#{x.containing_class.nsname}::NAME;"
@@ -92,6 +92,7 @@
       genl "o << \"]\";"
       genl "return o;"
     }
+    yield if block
   end
 
   # structs
@@ -103,13 +104,28 @@
   
   def action_h(a)
     action_struct_h(a, a.base, ["code"]) {
-      function_defn("template <class T> void invoke", ["T& target"]) {
-        genl "target.#{a.funcname}(#{a.values.join(', ')});"
+      struct("Handler") {
+        scope("void #{a.funcname}(", ");") {
+          genl a.parameters.join(",\n")
+        }
+      }
+      function_defn("template <class T> void invoke", ["T& target"], "const") {
+        genl "target.#{a.funcname}(#{a.values.join(', ')} );"
       }
     }
   end
   
-  def action_cpp(a) action_struct_cpp(a); end
+  def action_cpp(a)
+    action_struct_cpp(a) {
+      scope("void #{a.classname}::Handler::#{a.funcname}(", ")") {
+          genl a.unused_parameters.join(",\n")
+      }
+      scope {
+        genl "assert(0);"
+        genl "throw NotImplementedException(QPID_MSG(\"#{a.fqname} not 
implemented.\"));"
+      }
+    }
+  end
 
   # Types that must be generated early because they are used by other types.
   def pregenerate?(x) not @amqp.used_by[x.fqname].empty?;  end
@@ -172,6 +188,7 @@
 
     cpp_file("[EMAIL PROTECTED]/specification") { 
       include "[EMAIL PROTECTED]/specification"
+      include "[EMAIL PROTECTED]/exceptions"
       include "<iostream>"
       # FIXME aconway 2008-03-04: add Struct visitors.
       ["Command","Control"].each { |x| include "[EMAIL PROTECTED]/Apply#{x}" }

Modified: incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb?rev=646778&r1=646777&r2=646778&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb (original)
+++ incubator/qpid/trunk/qpid/cpp/rubygen/cppgen.rb Thu Apr 10 05:36:58 2008
@@ -152,6 +152,7 @@
 
 module AmqpHasFields
   def parameters() fields.map { |f| "#{f.paramtype} #{f.cppname}_"} end
+  def unused_parameters() fields.map { |f| "#{f.paramtype} /*#{f.cppname}_*/"} 
end
   def arguments() fields.map { |f| "#{f.cppname}_"} end
   def values() fields.map { |f| "#{f.cppname}"} end
   def initializers() fields.map { |f| "#{f.cppname}(#{f.cppname}_)"}  end

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Holder.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Holder.h?rev=646778&r1=646777&r2=646778&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Holder.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Holder.h Thu Apr 10 
05:36:58 2008
@@ -27,29 +27,36 @@
 namespace qpid {
 namespace amqp_0_10 {
 
+using framing::in_place;
+
+template <class Invokable> struct InvokeVisitor {
+    typedef void result_type;
+    Invokable& target;     
+    InvokeVisitor(Invokable& i) : target(i) {}
+
+    template <class Action>
+    void operator()(const Action& action) { action.invoke(target); }
+};
+
 template <class DerivedHolder, class BaseHeld, size_t Size>
-struct Holder : public framing::Blob<Size, BaseHeld> {
+class Holder : public framing::Blob<Size, BaseHeld> {
     typedef framing::Blob<Size, BaseHeld> Base;
-    
-    struct Assign : public ApplyFunctor<void> {
-        Holder& holder;
-        Assign(Holder& x) : holder(x) {}
-        template <class T> void operator()(const T& rhs) { holder=rhs; }
-    };
 
+  public:
+    
     Holder() {}
-    Holder(const BaseHeld& x) { *this=x; }
-    template <class T> Holder(const T& value) : Base(value) {}
+    template <class T> explicit Holder(const T& value) : Base(value) {}
 
     using Base::operator=;
-    Holder& operator=(const BaseHeld& rhs) {
-        Assign assign(*this);
-        apply(assign, rhs);
-        return *this;
-    }
+    Holder& operator=(const BaseHeld& rhs);
     
     uint8_t getCode() const { return this->get()->getCode(); }
     uint8_t getClassCode() const { return this->get()->getClassCode(); }
+
+    template <class Invokable> void invoke(Invokable& i) const {
+        InvokeVisitor<Invokable> v(i);
+        apply(v, *this->get());
+    }
     
     template <class S> void encode(S& s) const {
         s(getClassCode())(getCode());
@@ -65,7 +72,22 @@
         s.split(*this);
         apply(s, *this->get());
     }
+
+  private:
+    struct Assign : public ApplyFunctor<void> {
+        Holder& holder;
+        Assign(Holder& x) : holder(x) {}
+        template <class T> void operator()(const T& rhs) { holder=rhs; }
+    };
 };
+
+template <class D, class B, size_t S>
+Holder<D,B,S>& Holder<D,B,S>::operator=(const B& rhs) {
+    Assign assign(*this);
+    apply(assign, rhs);
+    return *this;
+}
+
 
 
 }} // namespace qpid::amqp_0_10

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Unit.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Unit.h?rev=646778&r1=646777&r2=646778&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Unit.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/amqp_0_10/Unit.h Thu Apr 10 05:36:58 
2008
@@ -34,15 +34,12 @@
 namespace qpid {
 namespace amqp_0_10 {
 
-
 /**
  * A Unit contains a frame header and associated value.
  * For all types except BODY the frame header is for a complete segment.
  */
 class Unit {
   public:
-    typedef boost::variant<ControlHolder, CommandHolder, Header, Body> Variant;
-
     explicit Unit(const FrameHeader& h=FrameHeader()) : header(h) { 
updateVariant(); }
 
     /**
@@ -57,12 +54,18 @@
     template<class T> const T* get() const { return boost::get<T>(&variant); }
     template<class T> T* get() { return boost::get<T>(&variant); }
     template<class T> Unit& operator=(const T& t) { variant=t; return *this; }
+
+    template <class V> typename V::result_type applyVisitor(V& v) const {
+        variant.apply_visitor(v); 
+    }
     
     template <class S> void serialize(S& s) { variant.apply_visitor(s); 
s.split(*this); }
     template <class S> void encode(S&) const {} 
     template <class S> void decode(S&) { updateHeader(header.getFlags()); }
 
   private:
+    typedef boost::variant<ControlHolder, CommandHolder, Header, Body> Variant;
+
     void updateHeader(uint8_t flags);
     void updateVariant();
     

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am?rev=646778&r1=646777&r2=646778&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am Thu Apr 10 05:36:58 2008
@@ -43,7 +43,8 @@
        amqp_0_10/ProxyTemplate.cpp \
        amqp_0_10/apply.cpp \
        IncompleteMessageList.cpp \
-       amqp_0_10/Map.cpp
+       amqp_0_10/Map.cpp \
+       amqp_0_10/handlers.cpp
 
 check_LTLIBRARIES += libshlibtest.la
 libshlibtest_la_LDFLAGS = -module -rpath $(abs_builddir)

Added: incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/handlers.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/handlers.cpp?rev=646778&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/handlers.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/handlers.cpp Thu Apr 10 
05:36:58 2008
@@ -0,0 +1,125 @@
+/*
+ *
+ * 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 "unit_test.h"
+#include "qpid/Exception.h"
+#include "qpid/amqp_0_10/Unit.h"
+#include "qpid/amqp_0_10/ControlHolder.h"
+#include "qpid/amqp_0_10/CommandHolder.h"
+#include "qpid/amqp_0_10/handlers.h"
+#include "qpid/amqp_0_10/specification.h"
+
+QPID_AUTO_TEST_SUITE(handler_tests)
+
+using namespace qpid::amqp_0_10;
+using namespace std;
+
+string called;                  // Set by called handler function
+
+// Note on handlers:
+// 
+// Control and Command handlers are separate, both behave the same way,
+// so substitute "control or command" for command in the following.
+//
+// Command handlers derive from CommandHandler and implement functions
+// for all the commands they handle. Handling an unimplemented command
+// will raise NotImplementedException.
+//
+// Using virtual inheritance from CommandHandler allows multiple
+// handlers to be aggregated into one with multiple inheritance,
+// See test code for example. 
+//
+// E.g. the existing broker model would have two control handlers:
+//  - ConnectionHandler: ControlHandler for connection controls.
+//  - SessionHandler: ControlHandler for session controls.
+// It would have class-command handlers for each AMQP class:  
+//    - QueueHandler, MessageHandler etc.. handle each class.
+// And an aggregate handler in place of BrokerAdapter
+//  - BrokerCommandHandler: public QueueHandler, MessageHandler ...
+//  
+// In other applications (e.g. cluster) any combination of commands
+// can be handled by a given handler. It _might_ simplify the code
+// to collaps ConnectionHandler and SessionHandler into a single
+// ControlHandler (or it might not.)
+
+struct TestExecutionHandler : public virtual CommandHandler {
+    void executionSync() { called = "executionSync"; }
+    // ... etc. for all execution commands
+};
+
+struct TestMessageHandler : public virtual CommandHandler {
+    void messageCancel(const Str8&)  { called="messageCancel"; }
+    // ... etc.
+};
+
+// Aggregate handler for all recognised commands.
+struct TestCommandHandler :
+    public TestExecutionHandler,
+    public TestMessageHandler
+    // ... etc. handlers for all command classes.
+{};                            // Nothing to do.
+
+
+// Sample unit handler, written as a static_visitor. 
+// Note it could equally be written with if/else statements
+// in handle.
+// 
+struct TestUnitHandler : public boost::static_visitor<void> {
+    TestCommandHandler handler;
+    void handle(const Unit& u) { u.applyVisitor(*this); }
+    
+    void operator()(const Body&)  { called="Body"; }
+    void operator()(const Header&) { called="Header"; }
+    void operator()(const ControlHolder&) { throw qpid::Exception("I don't do 
controls."); }
+    void operator()(const CommandHolder& c) { c.invoke(handler); }
+};
+
+BOOST_AUTO_TEST_CASE(testHandlers) {
+    TestUnitHandler handler;
+    Unit u;
+
+    u = Body();
+    handler.handle(u);
+    BOOST_CHECK_EQUAL("Body", called);
+
+    u = Header();
+    handler.handle(u);
+    BOOST_CHECK_EQUAL("Header", called);
+
+    // in_place<Foo>(...) is equivalent to Foo(...) but
+    // constructs Foo directly in the holder, avoiding
+    // a copy.
+    
+    u = CommandHolder(in_place<execution::Sync>());
+    handler.handle(u);
+    BOOST_CHECK_EQUAL("executionSync", called);
+
+    u = ControlHolder(in_place<connection::Start>(Map(), Str16Array(), 
Str16Array()));
+    try {
+        handler.handle(u);
+    } catch (const qpid::Exception&) {}
+
+    u = CommandHolder(in_place<message::Cancel>(Str8()));
+    handler.handle(u);
+    BOOST_CHECK_EQUAL("messageCancel", called);
+}
+
+QPID_AUTO_TEST_SUITE_END()

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/handlers.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/amqp_0_10/handlers.cpp
------------------------------------------------------------------------------
    svn:keywords = Rev Date


Reply via email to