[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