[asterisk-scf-commits] asterisk-scf/integration/ice-util-cpp.git branch "ami-collector" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Thu Jan 6 15:18:55 UTC 2011


branch "ami-collector" has been updated
       via  e0583da22e08670880bd69a3cd2d060ddd1652c9 (commit)
      from  d56505c33fa1901dd5de58d07cb115549e51cb90 (commit)

Summary of changes:
 AmiCollector/src/AmiCollector.h              |   92 ++++--------------
 AmiCollector/src/ResponseCollector.h         |  132 ++++++++++++++++++++++++++
 AmiCollector/test/AmiCollector-test.cpp      |   54 -----------
 AmiCollector/test/CMakeLists.txt             |    2 +-
 AmiCollector/test/ResponseCollector-test.cpp |  130 +++++++++++++++++++++++++
 AmiCollector/test/TestAmiCollector.h         |   11 +--
 6 files changed, 287 insertions(+), 134 deletions(-)
 create mode 100644 AmiCollector/src/ResponseCollector.h
 delete mode 100644 AmiCollector/test/AmiCollector-test.cpp
 create mode 100644 AmiCollector/test/ResponseCollector-test.cpp


- Log -----------------------------------------------------------------
commit e0583da22e08670880bd69a3cd2d060ddd1652c9
Author: David M. Lee <dlee at digium.com>
Date:   Thu Jan 6 08:45:57 2011 -0600

    Extracted a base ResponseCollector from AmiCollector.

diff --git a/AmiCollector/src/AmiCollector.h b/AmiCollector/src/AmiCollector.h
index a5ddbb9..892a136 100644
--- a/AmiCollector/src/AmiCollector.h
+++ b/AmiCollector/src/AmiCollector.h
@@ -16,13 +16,14 @@
 
 #pragma once
 
-#include <boost/thread/mutex.hpp>
 #include <Ice/Object.h>
 #include <Ice/Proxy.h>
 #include <Ice/OutgoingAsync.h>
 #include <IceUtil/Handle.h>
 #include <IceUtil/Shared.h>
 
+#include "ResponseCollector.h"
+
 namespace AsteriskSCF
 {
 namespace IceUtil
@@ -46,7 +47,9 @@ namespace IceUtil
 template<typename T,
          typename P,
          T (P::element_type::*EndFunction)(const Ice::AsyncResultPtr&)>
-class AmiCollector : public ::IceUtil::Shared
+class AmiCollector :
+        public ::IceUtil::Shared,
+        public ResponseCollector<const Ice::AsyncResultPtr&>
 {
 public:
     /** Proxy handle type (i.e. ObjectPrx) */
@@ -56,41 +59,29 @@ public:
     /** Return type for the end function */
     typedef T AsyncResultType;
     /** The type for AmiCollector itself */
-    typedef AmiCollector<T, P, EndFunction> Self;
+    typedef AmiCollector<T, P, EndFunction> AmiCollectorT;
 
     /**
-     * Constructor.
-     * @param numResponses The number of responses expected.
-     * @param end Pointer to the end function to call for responses.
+     * Creates an Ice CallbackPtr wrapper around this object, for use with AMI.
      */
-    AmiCollector(size_t numResponses) :
-        mNumResponses(numResponses)
+    Ice::CallbackPtr newIceCallback()
     {
+        // this happens prior to any callbacks, to no need to lock
+        return Ice::newCallback(this, &AmiCollectorT::invoke);
     }
 
     /**
-     * Creates an Ice CallbackPtr wrapper around this object, for use with AMI.
+     * While this looks useless, it's necessary so that the Ice callback can
+     * call the invoke function on the pointer we pass to it.
      */
-    Ice::CallbackPtr newIceCallback()
+    void invoke(const Ice::AsyncResultPtr& r)
     {
-        // this happens prior to any callbacks, to no need to lock
-
-        // handle the case where we don't expect any responses
-        // can't handle this in the ctor, since you can't call virtual
-        // functions in the constructor
-        if (mNumResponses == 0)
-        {
-            processCompletion();
-        }
-        return Ice::newCallback(this, &Self::finished);
+        ResponseCollectorT::invoke(r);
     }
 
-    /** The number of outstanding responses remaining. */
-    size_t getRemainingResponses() const { return mNumResponses; }
-
 protected:
     /** Protected dtor prevents creating instances on the stack */
-    ~AmiCollector() {}
+    virtual ~AmiCollector() {}
     /** Called for each response received. */
     virtual void processResult(AsyncResultType result) = 0;
     /** Called for each exception received. */
@@ -98,32 +89,18 @@ protected:
     /** Called after all the responses or exceptions have been accounted for. */
     virtual void processCompletion() {}
 
-    /**
-     * Thread safety for response counting.  Derived classes may use this for
-     * their own thread safety needs as well.
-     */
-    boost::mutex mMutex;
-
+private:
     /** Callback from Ice */
-    void finished(const Ice::AsyncResultPtr& r)
+    void processInvocation(const Ice::AsyncResultPtr& r)
     {
         try
         {
             try
             {
-                // unit test may not have an AsyncResultPtr
-                if (r)
-                {
-                    IceProxy p = IceProxy::uncheckedCast(r->getProxy());
-                    // invoke the nd function on our proxy, passing in r
-                    // the results are passed to processResult
-                    processResult(((*p).*EndFunction)(r));
-                }
-                else
-                {
-                    // we didn't have an AsyncResultPtr, so make something up
-                    processResult(AsyncResultType());
-                }
+                IceProxy p = IceProxy::uncheckedCast(r->getProxy());
+                // invoke the end function on our proxy, passing in r
+                // the results are passed to processResult
+                processResult(((*p).*EndFunction)(r));
             }
             catch(const Ice::Exception& e)
             {
@@ -142,33 +119,6 @@ protected:
             std::clog << "Unexpected exception\n";
             assert(false);
         }
-        countResponse();
-    }
-
-private:
-    size_t mNumResponses;
-
-    /**
-     * Called from each AMI callback.  When this function sees that the expected
-     * number of responses have been received, it invokes
-     * <code>processCompletion</code>
-     */
-    void countResponse()
-    {
-        bool done = false;
-        {
-            boost::lock_guard<boost::mutex> lock(mMutex);
-            assert(mNumResponses > 0); // we got more responses than expected
-            if (--mNumResponses == 0)
-            {
-                done = true;
-            }
-        }
-
-        if (done)
-        {
-            processCompletion();
-        }
     }
 };
 
diff --git a/AmiCollector/src/ResponseCollector.h b/AmiCollector/src/ResponseCollector.h
new file mode 100644
index 0000000..44e7b6c
--- /dev/null
+++ b/AmiCollector/src/ResponseCollector.h
@@ -0,0 +1,132 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+
+#pragma once
+
+#include <boost/thread/mutex.hpp>
+#include <iostream>
+
+namespace AsteriskSCF
+{
+
+class TooManyInvocations : public std::exception
+{
+public:
+    const char* what() const throw ()
+    {
+        return "ResponseCollector invoked too many times";
+    }
+};
+
+/**
+ * Collects the results for multiple asynchronous responses.  While the response
+ * counting logic is properly locked and thread safe, it is incumbent upon the
+ * implementor of the <code>processInvocation</code> functions to write those
+ * functions to be thread safe.  Derived classes may use mMutex for their own
+ * locking.
+ */
+template<typename T>
+class ResponseCollector
+{
+public:
+    typedef T InvocationParamType;
+    typedef ResponseCollector<T> ResponseCollectorT;
+
+    /**
+     * Constructor.  The collector is no good until it's been initialized.
+     */
+    ResponseCollector() :
+        mNumResponses(0)
+    {
+    }
+
+    virtual ~ResponseCollector() {}
+
+    /**
+     * Initialize the collector.
+     * @param numResponses The number of responses expected.
+     */
+    void init(size_t numResponses)
+    {
+        mNumResponses = numResponses;
+        // handle the case where we expect no responses
+        if (numResponses == 0)
+        {
+            processCompletion();
+        }
+    }
+
+    /**
+     * Invoke this function for every response.
+     */
+    void invoke(InvocationParamType param)
+    {
+        try
+        {
+            processInvocation(param);
+        }
+        catch(...)
+        {
+            countResponse();
+            throw;
+        }
+        countResponse();
+    }
+
+protected:
+    /** Called to retrieve the results for an invocation */
+    virtual void processInvocation(InvocationParamType param) = 0;
+    /** Called after all the responses or exceptions have been accounted for. */
+    virtual void processCompletion() {}
+
+    /**
+     * Thread safety for response counting.  Derived classes may use this for
+     * their own thread safety needs as well.
+     */
+    boost::mutex mMutex;
+
+private:
+    size_t mNumResponses;
+
+    /**
+     * Called from each AMI callback.  When this function sees that the expected
+     * number of responses have been received, it invokes
+     * <code>processCompletion</code>
+     */
+    void countResponse()
+    {
+        bool done = false;
+        {
+            boost::lock_guard<boost::mutex> lock(mMutex);
+            if (mNumResponses <= 0)
+            {
+                throw TooManyInvocations();
+            }
+
+            if (--mNumResponses == 0)
+            {
+                done = true;
+            }
+        }
+
+        if (done)
+        {
+            processCompletion();
+        }
+    }
+};
+
+} // AsteriskSCF
diff --git a/AmiCollector/test/AmiCollector-test.cpp b/AmiCollector/test/AmiCollector-test.cpp
deleted file mode 100644
index 05f2973..0000000
--- a/AmiCollector/test/AmiCollector-test.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Asterisk SCF -- An open-source communications framework.
- *
- * Copyright (C) 2010, Digium, Inc.
- *
- * See http://www.asterisk.org for more information about
- * the Asterisk SCF project. Please do not directly contact
- * any of the maintainers of this project for assistance;
- * the project provides a web site, mailing lists and IRC
- * channels for your use.
- *
- * This program is free software, distributed under the terms of
- * the GNU General Public License Version 2. See the LICENSE.txt file
- * at the top of the source tree.
- */
-
-#include <boost/test/unit_test.hpp>
-
-#include "AmiCollector.h"
-#include "TestAmiCollector.h"
-
-using namespace AsteriskSCF::IceUtil;
-
-BOOST_AUTO_TEST_SUITE(AmiCollectorTest)
-
-BOOST_AUTO_TEST_CASE(test_zero)
-{
-    TestAmiCollectorPtr uut = new TestAmiCollector(0);
-
-    uut->newIceCallback();
-
-    BOOST_CHECK_EQUAL(0, uut->results);
-    BOOST_CHECK_EQUAL(0, uut->exceptions);
-    BOOST_CHECK_EQUAL(true, uut->complete);
-}
-
-BOOST_AUTO_TEST_CASE(test_one)
-{
-    TestAmiCollectorPtr uut = new TestAmiCollector(1);
-
-    uut->newIceCallback();
-
-    BOOST_CHECK_EQUAL(0, uut->results);
-    BOOST_CHECK_EQUAL(0, uut->exceptions);
-    BOOST_CHECK_EQUAL(false, uut->complete);
-
-    uut->finished(0);
-
-    BOOST_CHECK_EQUAL(1, uut->results);
-    BOOST_CHECK_EQUAL(0, uut->exceptions);
-    BOOST_CHECK_EQUAL(true, uut->complete);
-}
-
-BOOST_AUTO_TEST_SUITE_END()
diff --git a/AmiCollector/test/CMakeLists.txt b/AmiCollector/test/CMakeLists.txt
index 952caf0..5dbb40b 100644
--- a/AmiCollector/test/CMakeLists.txt
+++ b/AmiCollector/test/CMakeLists.txt
@@ -1,7 +1,7 @@
 asterisk_scf_component_init(ami-collector-test CXX)
 include_directories("../src")
 
-asterisk_scf_component_add_file(ami-collector-test AmiCollector-test.cpp)
+asterisk_scf_component_add_file(ami-collector-test ResponseCollector-test.cpp)
 asterisk_scf_component_add_file(ami-collector-test IceIntegration-test.cpp)
 asterisk_scf_component_add_file(ami-collector-test TestAmiCollector.h)
 asterisk_scf_component_add_file(ami-collector-test test.cpp)
diff --git a/AmiCollector/test/ResponseCollector-test.cpp b/AmiCollector/test/ResponseCollector-test.cpp
new file mode 100644
index 0000000..34bb0f3
--- /dev/null
+++ b/AmiCollector/test/ResponseCollector-test.cpp
@@ -0,0 +1,130 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk SCF project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE.txt file
+ * at the top of the source tree.
+ */
+
+#include <boost/test/unit_test.hpp>
+
+#include "ResponseCollector.h"
+
+using namespace AsteriskSCF;
+
+namespace
+{
+class TestException : std::exception
+{
+public:
+    const char* what() const throw() { return "TestException"; }
+};
+
+class TestCollector : public ResponseCollector<bool>
+{
+public:
+    /** Num results received */
+    int results;
+    /** Is complete? */
+    bool complete;
+
+    TestCollector() : results(0), complete(false) {}
+
+    void processInvocation(bool shouldThrow)
+    {
+        ++results;
+        if (shouldThrow)
+        {
+            throw TestException();
+        }
+    }
+    void processCompletion()
+    {
+        BOOST_CHECK_EQUAL(false, complete);
+        complete = true;
+    }
+};
+
+} // namespace
+
+BOOST_AUTO_TEST_SUITE(AmiCollectorTest)
+
+BOOST_AUTO_TEST_CASE(test_zero)
+{
+    TestCollector uut;
+
+    uut.init(0);
+
+    BOOST_CHECK_EQUAL(0, uut.results);
+    BOOST_CHECK_EQUAL(true, uut.complete);
+}
+
+BOOST_AUTO_TEST_CASE(test_one)
+{
+    TestCollector uut;
+
+    uut.init(1);
+
+    BOOST_CHECK_EQUAL(0, uut.results);
+    BOOST_CHECK_EQUAL(false, uut.complete);
+
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+
+    BOOST_CHECK_EQUAL(1, uut.results);
+    BOOST_CHECK_EQUAL(true, uut.complete);
+}
+
+BOOST_AUTO_TEST_CASE(test_one_exception)
+{
+    TestCollector uut;
+
+    uut.init(1);
+
+    uut.invoke(false);
+
+    BOOST_CHECK_EQUAL(1, uut.results);
+    BOOST_CHECK_EQUAL(true, uut.complete);
+}
+
+BOOST_AUTO_TEST_CASE(test_many)
+{
+    TestCollector uut;
+
+    uut.init(5);
+
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+    BOOST_CHECK_EQUAL(false, uut.complete);
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+
+    BOOST_CHECK_EQUAL(5, uut.results);
+    BOOST_CHECK_EQUAL(true, uut.complete);
+}
+
+BOOST_AUTO_TEST_CASE(test_mixed)
+{
+    TestCollector uut;
+
+    uut.init(5);
+
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+    uut.invoke(false);
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+    uut.invoke(false);
+    try { uut.invoke(true); } catch (...) { /* ignore */ }
+
+    BOOST_CHECK_EQUAL(5, uut.results);
+    BOOST_CHECK_EQUAL(true, uut.complete);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/AmiCollector/test/TestAmiCollector.h b/AmiCollector/test/TestAmiCollector.h
index 6291702..11ae789 100644
--- a/AmiCollector/test/TestAmiCollector.h
+++ b/AmiCollector/test/TestAmiCollector.h
@@ -34,11 +34,12 @@ class TestAmiCollector : public AsteriskSCF::IceUtil::AmiCollector<
 {
 public:
     explicit TestAmiCollector(size_t n) :
-        Self(n),
         results(0),
         exceptions(0),
         complete(false)
-    {}
+    {
+        init(n);
+    }
     /** Num results received */
     int results;
     /** Num exceptions received */
@@ -46,12 +47,6 @@ public:
     /** Is complete? */
     bool complete;
 
-    /** Exposes the 'finished' callback function for unit testing. */
-    void finished(const Ice::AsyncResultPtr& r)
-    {
-        Self::finished(r);
-    }
-
     /** Blocks until processCompletion is called. */
     void waitForCompletion()
     {

-----------------------------------------------------------------------


-- 
asterisk-scf/integration/ice-util-cpp.git



More information about the asterisk-scf-commits mailing list