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

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Wed Jan 5 22:06:37 UTC 2011


branch "ami-collector" has been created
        at  d56505c33fa1901dd5de58d07cb115549e51cb90 (commit)

- Log -----------------------------------------------------------------
commit d56505c33fa1901dd5de58d07cb115549e51cb90
Author: David M. Lee <dlee at digium.com>
Date:   Wed Jan 5 16:02:10 2011 -0600

    cleanup

diff --git a/AmiCollector/src/AmiCollector.h b/AmiCollector/src/AmiCollector.h
index 5e7e605..a5ddbb9 100644
--- a/AmiCollector/src/AmiCollector.h
+++ b/AmiCollector/src/AmiCollector.h
@@ -33,8 +33,19 @@ namespace IceUtil
  * counting logic is properly locked and thread safe, it is incumbent upon the
  * implementor of the <code>process*</code> functions to write those functions
  * to be thread safe.  Derived classes may use mMutex for their own locking.
+ *
+ * An example of the template parameters would be:
+ * <code>
+ *   <bool, Ice::ObjectPrx, &Ice::ObjectPrx::element_type::end_ice_isA>
+ * </code>
+ *
+ * @param T The asynchronous result type (return value from end function)
+ * @param P The type of the proxy class
+ * @param EndFunction The pointer to member function for the end_ function
  */
-template<typename T, typename P, T (P::element_type::*EndFunction)(const Ice::AsyncResultPtr&)>
+template<typename T,
+         typename P,
+         T (P::element_type::*EndFunction)(const Ice::AsyncResultPtr&)>
 class AmiCollector : public ::IceUtil::Shared
 {
 public:
diff --git a/AmiCollector/test/TestAmiCollector.h b/AmiCollector/test/TestAmiCollector.h
index b3cb484..6291702 100644
--- a/AmiCollector/test/TestAmiCollector.h
+++ b/AmiCollector/test/TestAmiCollector.h
@@ -27,7 +27,10 @@ namespace IceUtil
 /**
  * Simple AMI collector for testing
  */
-class TestAmiCollector : public AsteriskSCF::IceUtil::AmiCollector<bool, Ice::ObjectPrx, &Ice::ObjectPrx::element_type::end_ice_isA>
+class TestAmiCollector : public AsteriskSCF::IceUtil::AmiCollector<
+    bool,
+    Ice::ObjectPrx,
+    &Ice::ObjectPrx::element_type::end_ice_isA>
 {
 public:
     explicit TestAmiCollector(size_t n) :

commit 676800cd66e893d4c171603dbe83e703754b23fa
Author: David M. Lee <dlee at digium.com>
Date:   Wed Jan 5 15:56:14 2011 -0600

    PTMF is now template param.

diff --git a/AmiCollector/src/AmiCollector.h b/AmiCollector/src/AmiCollector.h
index dcae2b9..5e7e605 100644
--- a/AmiCollector/src/AmiCollector.h
+++ b/AmiCollector/src/AmiCollector.h
@@ -34,29 +34,26 @@ namespace IceUtil
  * implementor of the <code>process*</code> functions to write those functions
  * to be thread safe.  Derived classes may use mMutex for their own locking.
  */
-template<typename T, typename P>
+template<typename T, typename P, T (P::element_type::*EndFunction)(const Ice::AsyncResultPtr&)>
 class AmiCollector : public ::IceUtil::Shared
 {
 public:
     /** Proxy handle type (i.e. ObjectPrx) */
     typedef P IceProxy;
     /** Proxy element type (i.e. Proxy::Ice::Object) */
-    typedef typename IceProxy::element_type ElementType;
+    typedef typename P::element_type ElementType;
     /** Return type for the end function */
     typedef T AsyncResultType;
     /** The type for AmiCollector itself */
-    typedef AmiCollector<T, P> Self;
-    /** Pointer to member function for the end function */
-    typedef AsyncResultType (ElementType::*EndFunction)(const Ice::AsyncResultPtr&);
+    typedef AmiCollector<T, P, EndFunction> Self;
 
     /**
      * Constructor.
      * @param numResponses The number of responses expected.
      * @param end Pointer to the end function to call for responses.
      */
-    AmiCollector(size_t numResponses, EndFunction end) :
-        mNumResponses(numResponses),
-        mEnd(end)
+    AmiCollector(size_t numResponses) :
+        mNumResponses(numResponses)
     {
     }
 
@@ -107,9 +104,9 @@ protected:
                 if (r)
                 {
                     IceProxy p = IceProxy::uncheckedCast(r->getProxy());
-                    // invoke the mEnd function on our proxy, passing in r
+                    // invoke the nd function on our proxy, passing in r
                     // the results are passed to processResult
-                    processResult(((*p).*mEnd)(r));
+                    processResult(((*p).*EndFunction)(r));
                 }
                 else
                 {
@@ -139,7 +136,6 @@ protected:
 
 private:
     size_t mNumResponses;
-    EndFunction mEnd;
 
     /**
      * Called from each AMI callback.  When this function sees that the expected
diff --git a/AmiCollector/test/TestAmiCollector.h b/AmiCollector/test/TestAmiCollector.h
index 6471897..b3cb484 100644
--- a/AmiCollector/test/TestAmiCollector.h
+++ b/AmiCollector/test/TestAmiCollector.h
@@ -27,11 +27,11 @@ namespace IceUtil
 /**
  * Simple AMI collector for testing
  */
-class TestAmiCollector : public AsteriskSCF::IceUtil::AmiCollector<bool, Ice::ObjectPrx>
+class TestAmiCollector : public AsteriskSCF::IceUtil::AmiCollector<bool, Ice::ObjectPrx, &Ice::ObjectPrx::element_type::end_ice_isA>
 {
 public:
     explicit TestAmiCollector(size_t n) :
-        Self(n, &IceProxy::element_type::end_ice_isA),
+        Self(n),
         results(0),
         exceptions(0),
         complete(false)

commit 58459137b2dbc653f98dacc6f8c7da891f0c7ae7
Author: David M. Lee <dlee at digium.com>
Date:   Wed Jan 5 15:27:33 2011 -0600

    Now I feel good about the AmiCollector :-)

diff --git a/AmiCollector/src/AmiCollector.h b/AmiCollector/src/AmiCollector.h
index 98d0998..dcae2b9 100644
--- a/AmiCollector/src/AmiCollector.h
+++ b/AmiCollector/src/AmiCollector.h
@@ -29,90 +29,117 @@ namespace IceUtil
 {
 
 /**
- * Collects the results for multiple asynchronous responses.  While the vote
+ * 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>process*</code> functions to write those functions
- * to be thread safe.  Feel free to use mMutex (it's protected) if needed.
+ * to be thread safe.  Derived classes may use mMutex for their own locking.
  */
-template<typename T>
+template<typename T, typename P>
 class AmiCollector : public ::IceUtil::Shared
 {
 public:
+    /** Proxy handle type (i.e. ObjectPrx) */
+    typedef P IceProxy;
+    /** Proxy element type (i.e. Proxy::Ice::Object) */
+    typedef typename IceProxy::element_type ElementType;
+    /** Return type for the end function */
     typedef T AsyncResultType;
-    typedef AmiCollector<T> Self;
+    /** The type for AmiCollector itself */
+    typedef AmiCollector<T, P> Self;
+    /** Pointer to member function for the end function */
+    typedef AsyncResultType (ElementType::*EndFunction)(const Ice::AsyncResultPtr&);
 
-    AmiCollector(size_t numVotes) : mNumVotes(numVotes)
+    /**
+     * Constructor.
+     * @param numResponses The number of responses expected.
+     * @param end Pointer to the end function to call for responses.
+     */
+    AmiCollector(size_t numResponses, EndFunction end) :
+        mNumResponses(numResponses),
+        mEnd(end)
     {
     }
 
     /**
      * Creates an Ice CallbackPtr wrapper around this object, for use with AMI.
      */
-    Ice::CallbackPtr toIceCallback()
+    Ice::CallbackPtr newIceCallback()
     {
         // 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 (mNumVotes == 0)
+        if (mNumResponses == 0)
         {
             processCompletion();
         }
         return Ice::newCallback(this, &Self::finished);
     }
 
-    size_t getRemainingVotes() const { return mNumVotes; }
+    /** The number of outstanding responses remaining. */
+    size_t getRemainingResponses() const { return mNumResponses; }
 
 protected:
     /** Protected dtor prevents creating instances on the stack */
     ~AmiCollector() {}
-    /**
-     * Wrapper to correctly end the remote function call.
-     * Should almost always look like:
-     * <code>
-     *  DerivedPrx d = DerivedPrx::uncheckedCast(r->getProxy());
-     *  return d->end_remoteFunction(r);
-     * </code>
-     */
-    virtual AsyncResultType end(const Ice::AsyncResultPtr& proxy) = 0;
-    /**
-     * Called for each response received.
-     */
+    /** Called for each response received. */
     virtual void processResult(AsyncResultType result) = 0;
-    /**
-     * Called for each exception received.
-     */
+    /** Called for each exception received. */
     virtual void processException(const Ice::Exception& e) = 0;
-    /**
-     * Called after all the responses or exceptions have been accounted for.
-     */
+    /** 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;
 
+    /** Callback from Ice */
     void finished(const Ice::AsyncResultPtr& r)
     {
         try
         {
             try
             {
-                processResult(end(r));
+                // unit test may not have an AsyncResultPtr
+                if (r)
+                {
+                    IceProxy p = IceProxy::uncheckedCast(r->getProxy());
+                    // invoke the mEnd function on our proxy, passing in r
+                    // the results are passed to processResult
+                    processResult(((*p).*mEnd)(r));
+                }
+                else
+                {
+                    // we didn't have an AsyncResultPtr, so make something up
+                    processResult(AsyncResultType());
+                }
             }
             catch(const Ice::Exception& e)
             {
                 processException(e);
             }
         }
+        catch(const std::exception& e)
+        {
+            // any exceptions thrown during processing are programming errors
+            std::clog << "Unexpected exception: " << e.what() << '\n';
+            assert(false);
+        }
         catch(...)
         {
-            // ignore any processing exceptions
+            // and _please_ don't just throw char pointers :-(
+            std::clog << "Unexpected exception\n";
+            assert(false);
         }
         countResponse();
     }
 
 private:
-    size_t mNumVotes;
+    size_t mNumResponses;
+    EndFunction mEnd;
 
     /**
      * Called from each AMI callback.  When this function sees that the expected
@@ -124,8 +151,8 @@ private:
         bool done = false;
         {
             boost::lock_guard<boost::mutex> lock(mMutex);
-            assert(mNumVotes > 0); // we got more responses than expected
-            if (--mNumVotes == 0)
+            assert(mNumResponses > 0); // we got more responses than expected
+            if (--mNumResponses == 0)
             {
                 done = true;
             }
diff --git a/AmiCollector/test/AmiCollector-test.cpp b/AmiCollector/test/AmiCollector-test.cpp
index 6f659e1..05f2973 100644
--- a/AmiCollector/test/AmiCollector-test.cpp
+++ b/AmiCollector/test/AmiCollector-test.cpp
@@ -14,74 +14,20 @@
  * at the top of the source tree.
  */
 
-#include <Ice/Proxy.h>
 #include <boost/test/unit_test.hpp>
 
 #include "AmiCollector.h"
+#include "TestAmiCollector.h"
 
 using namespace AsteriskSCF::IceUtil;
 
-namespace
-{
-class TestAmiCollector : public AsteriskSCF::IceUtil::AmiCollector<bool>
-{
-public:
-    explicit TestAmiCollector(size_t n) :
-        AmiCollector<bool>(n),
-        results(0),
-        exceptions(0),
-        complete(false)
-    {}
-    int results;
-    int exceptions;
-    bool complete;
-
-    void finished(const Ice::AsyncResultPtr& r)
-    {
-        Self::finished(r);
-    }
-
-protected:
-    ~TestAmiCollector() {}
-    virtual AsyncResultType end(const Ice::AsyncResultPtr& proxy)
-    {
-        // fake - do nothing
-        return false;
-    }
-    void processResult(AsyncResultType result)
-    {
-        ++results;
-    }
-    void processException(const Ice::Exception& e)
-    {
-        ++exceptions;
-    }
-    void processCompletion()
-    {
-        BOOST_CHECK_EQUAL(false, complete);
-        complete = true;
-    }
-};
-
-typedef IceUtil::Handle<TestAmiCollector> TestAmiCollectorPtr;
-
-template<typename T>
-Ice::CallbackPtr noCallbackPtr(const IceUtil::Handle<T>& ptr,
-    void (T::*cb)(const int&),
-    void (T::*excb)(const Ice::Exception&),
-    void (T::*sentcb)(bool) = 0)
-{
-    return Ice::CallbackPtr();
-}
-}
-
 BOOST_AUTO_TEST_SUITE(AmiCollectorTest)
 
 BOOST_AUTO_TEST_CASE(test_zero)
 {
     TestAmiCollectorPtr uut = new TestAmiCollector(0);
 
-    uut->toIceCallback();
+    uut->newIceCallback();
 
     BOOST_CHECK_EQUAL(0, uut->results);
     BOOST_CHECK_EQUAL(0, uut->exceptions);
@@ -92,7 +38,7 @@ BOOST_AUTO_TEST_CASE(test_one)
 {
     TestAmiCollectorPtr uut = new TestAmiCollector(1);
 
-    uut->toIceCallback();
+    uut->newIceCallback();
 
     BOOST_CHECK_EQUAL(0, uut->results);
     BOOST_CHECK_EQUAL(0, uut->exceptions);
diff --git a/AmiCollector/test/CMakeLists.txt b/AmiCollector/test/CMakeLists.txt
index eb59de6..952caf0 100644
--- a/AmiCollector/test/CMakeLists.txt
+++ b/AmiCollector/test/CMakeLists.txt
@@ -2,9 +2,11 @@ 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 IceIntegration-test.cpp)
+asterisk_scf_component_add_file(ami-collector-test TestAmiCollector.h)
 asterisk_scf_component_add_file(ami-collector-test test.cpp)
 
-asterisk_scf_component_add_boost_libraries(ami-collector-test unit_test_framework)
+asterisk_scf_component_add_boost_libraries(ami-collector-test unit_test_framework thread)
 
 asterisk_scf_component_build_standalone(ami-collector-test)
 
diff --git a/AmiCollector/test/IceIntegration-test.cpp b/AmiCollector/test/IceIntegration-test.cpp
new file mode 100644
index 0000000..343ef1e
--- /dev/null
+++ b/AmiCollector/test/IceIntegration-test.cpp
@@ -0,0 +1,120 @@
+/*
+ * 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 <unistd.h>
+
+#include <Ice/Ice.h>
+#include <Ice/Proxy.h>
+#include <boost/test/unit_test.hpp>
+
+#include "AmiCollector.h"
+#include "TestAmiCollector.h"
+
+using namespace AsteriskSCF::IceUtil;
+
+namespace
+{
+class MyObject : public Ice::Object{};
+
+struct Fixture
+{
+    Fixture() :
+        communicator(Ice::initialize()),
+        adapter(communicator->createObjectAdapterWithEndpoints("test", "default")),
+        object(new MyObject),
+        proxy(adapter->addWithUUID(object)->ice_collocationOptimized(false))
+    {
+        adapter->activate();
+    }
+
+    ~Fixture()
+    {
+        communicator->shutdown();
+        communicator->waitForShutdown();
+    }
+
+    Ice::CommunicatorPtr communicator;
+    Ice::ObjectAdapterPtr adapter;
+    Ice::ObjectPtr object;
+    Ice::ObjectPrx proxy;
+};
+} // anonymous namespace
+
+BOOST_FIXTURE_TEST_SUITE(AmiCollectorIceIntegration, Fixture)
+
+BOOST_AUTO_TEST_CASE(test_zero)
+{
+    TestAmiCollectorPtr uut = new TestAmiCollector(0);
+    uut->newIceCallback();
+
+    uut->waitForCompletion();
+
+    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);
+
+    BOOST_CHECK_EQUAL(0, uut->results);
+    BOOST_CHECK_EQUAL(0, uut->exceptions);
+    BOOST_CHECK_EQUAL(false, uut->complete);
+
+    proxy->begin_ice_isA("::Ice::Object", uut->newIceCallback());
+
+    uut->waitForCompletion();
+
+    BOOST_CHECK_EQUAL(1, uut->results);
+    BOOST_CHECK_EQUAL(0, uut->exceptions);
+    BOOST_CHECK_EQUAL(true, uut->complete);
+}
+
+BOOST_AUTO_TEST_CASE(test_exception)
+{
+    TestAmiCollectorPtr uut = new TestAmiCollector(1);
+
+    // by destroying the adapter, we should get an exception back
+    adapter->destroy();
+
+    proxy->begin_ice_isA("object was shutdown", uut->newIceCallback());
+
+    uut->waitForCompletion();
+
+    BOOST_CHECK_EQUAL(0, uut->results);
+    BOOST_CHECK_EQUAL(1, uut->exceptions);
+    BOOST_CHECK_EQUAL(true, uut->complete);
+}
+
+BOOST_AUTO_TEST_CASE(test_some)
+{
+    TestAmiCollectorPtr uut = new TestAmiCollector(5);
+
+    proxy->begin_ice_isA("::Ice::Object", uut->newIceCallback());
+    proxy->begin_ice_isA("::Ice::Object", uut->newIceCallback());
+    proxy->begin_ice_isA("::Ice::Object", uut->newIceCallback());
+    proxy->begin_ice_isA("::Ice::Object", uut->newIceCallback());
+    proxy->begin_ice_isA("::Ice::Object", uut->newIceCallback());
+
+    uut->waitForCompletion();
+
+    BOOST_CHECK_EQUAL(5, uut->results);
+    BOOST_CHECK_EQUAL(0, uut->exceptions);
+    BOOST_CHECK_EQUAL(true, uut->complete);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/AmiCollector/test/TestAmiCollector.h b/AmiCollector/test/TestAmiCollector.h
new file mode 100644
index 0000000..6471897
--- /dev/null
+++ b/AmiCollector/test/TestAmiCollector.h
@@ -0,0 +1,87 @@
+/*
+ * 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/thread/condition_variable.hpp>
+#include <IceUtil/Handle.h>
+
+#include "AmiCollector.h"
+
+namespace AsteriskSCF
+{
+namespace IceUtil
+{
+
+/**
+ * Simple AMI collector for testing
+ */
+class TestAmiCollector : public AsteriskSCF::IceUtil::AmiCollector<bool, Ice::ObjectPrx>
+{
+public:
+    explicit TestAmiCollector(size_t n) :
+        Self(n, &IceProxy::element_type::end_ice_isA),
+        results(0),
+        exceptions(0),
+        complete(false)
+    {}
+    /** Num results received */
+    int results;
+    /** Num exceptions received */
+    int exceptions;
+    /** 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()
+    {
+        boost::unique_lock<boost::mutex> lock(mMutex);
+        while (!complete)
+        {
+            cond.wait(lock);
+        }
+    }
+
+protected:
+    ~TestAmiCollector() {}
+    void processResult(AsyncResultType result)
+    {
+        ++results;
+    }
+    void processException(const Ice::Exception& e)
+    {
+        ++exceptions;
+    }
+    void processCompletion()
+    {
+        boost::unique_lock<boost::mutex> lock(mMutex);
+        BOOST_CHECK_EQUAL(false, complete);
+        complete = true;
+        cond.notify_all();
+    }
+
+private:
+    boost::condition_variable cond;
+};
+
+typedef ::IceUtil::Handle<TestAmiCollector> TestAmiCollectorPtr;
+
+} // IceUtil
+} // AsteriskSCF

commit 595d005e52185c8c7f1c1f8ed1486073cea2478b
Author: David M. Lee <dlee at digium.com>
Date:   Wed Jan 5 13:27:22 2011 -0600

    Improved AmiCollector.
    
    By using the generic callback, ironically I've reduced the number of
    type problems I had with the code.

diff --git a/AmiCollector/src/AmiCollector.h b/AmiCollector/src/AmiCollector.h
index b01e74b..98d0998 100644
--- a/AmiCollector/src/AmiCollector.h
+++ b/AmiCollector/src/AmiCollector.h
@@ -48,12 +48,7 @@ public:
     /**
      * Creates an Ice CallbackPtr wrapper around this object, for use with AMI.
      */
-    template<typename CB, typename HN>
-    IceInternal::CallbackBasePtr toIceCallback(CB (*newCallbackFunction)
-        (HN,
-            void (Self::*cb)(T),
-            void (Self::*excb)(const ::Ice::Exception&),
-            void (Self::*sentcb)(bool)))
+    Ice::CallbackPtr toIceCallback()
     {
         // this happens prior to any callbacks, to no need to lock
 
@@ -64,10 +59,7 @@ public:
         {
             processCompletion();
         }
-        return newCallbackFunction(this,
-            &AmiCollector<AsyncResultType>::resultCallback,
-            &AmiCollector<AsyncResultType>::errorCallback,
-            0 /* sentCallback */);
+        return Ice::newCallback(this, &Self::finished);
     }
 
     size_t getRemainingVotes() const { return mNumVotes; }
@@ -76,6 +68,15 @@ protected:
     /** Protected dtor prevents creating instances on the stack */
     ~AmiCollector() {}
     /**
+     * Wrapper to correctly end the remote function call.
+     * Should almost always look like:
+     * <code>
+     *  DerivedPrx d = DerivedPrx::uncheckedCast(r->getProxy());
+     *  return d->end_remoteFunction(r);
+     * </code>
+     */
+    virtual AsyncResultType end(const Ice::AsyncResultPtr& proxy) = 0;
+    /**
      * Called for each response received.
      */
     virtual void processResult(AsyncResultType result) = 0;
@@ -88,41 +89,28 @@ protected:
      */
     virtual void processCompletion() {}
 
-    /**
-     * AMI result callback.
-     */
-    void resultCallback(AsyncResultType result)
-    {
-        try
-        {
-            processResult(result);
-        }
-        catch(...)
-        {
-            countResponse();
-            throw;
-        }
-        countResponse();
-    }
+    boost::mutex mMutex;
 
-    /**
-     * AMI exception callback.
-     */
-    void errorCallback(const Ice::Exception& e)
+    void finished(const Ice::AsyncResultPtr& r)
     {
         try
         {
-            processException(e);
+            try
+            {
+                processResult(end(r));
+            }
+            catch(const Ice::Exception& e)
+            {
+                processException(e);
+            }
         }
         catch(...)
         {
-            countResponse();
-            throw;
+            // ignore any processing exceptions
         }
         countResponse();
     }
 
-    boost::mutex mMutex;
 private:
     size_t mNumVotes;
 
diff --git a/AmiCollector/test/AmiCollector-test.cpp b/AmiCollector/test/AmiCollector-test.cpp
index 92f1b1c..6f659e1 100644
--- a/AmiCollector/test/AmiCollector-test.cpp
+++ b/AmiCollector/test/AmiCollector-test.cpp
@@ -36,17 +36,18 @@ public:
     int exceptions;
     bool complete;
 
-    void resultCallback(AsyncResultType result)
+    void finished(const Ice::AsyncResultPtr& r)
     {
-        AmiCollector<bool>::resultCallback(result);
-    }
-    void errorCallback(const Ice::Exception& e)
-    {
-        AmiCollector<bool>::errorCallback(e);
+        Self::finished(r);
     }
 
 protected:
     ~TestAmiCollector() {}
+    virtual AsyncResultType end(const Ice::AsyncResultPtr& proxy)
+    {
+        // fake - do nothing
+        return false;
+    }
     void processResult(AsyncResultType result)
     {
         ++results;
@@ -80,13 +81,7 @@ BOOST_AUTO_TEST_CASE(test_zero)
 {
     TestAmiCollectorPtr uut = new TestAmiCollector(0);
 
-    Ice::Callback_Object_ice_isAPtr (*factory)
-        (const IceUtil::Handle<AmiCollector<bool> >& instance,
-            void (AmiCollector<bool>::*cb)(bool),
-            void (AmiCollector<bool>::*excb)(const ::Ice::Exception&),
-            void (AmiCollector<bool>::*sentcb)(bool)) = Ice::newCallback_Object_ice_isA;
-
-    uut->toIceCallback(factory);
+    uut->toIceCallback();
 
     BOOST_CHECK_EQUAL(0, uut->results);
     BOOST_CHECK_EQUAL(0, uut->exceptions);
@@ -97,19 +92,13 @@ BOOST_AUTO_TEST_CASE(test_one)
 {
     TestAmiCollectorPtr uut = new TestAmiCollector(1);
 
-    Ice::Callback_Object_ice_isAPtr (*factory)
-        (const IceUtil::Handle<AmiCollector<bool> >& instance,
-            void (AmiCollector<bool>::*cb)(bool),
-            void (AmiCollector<bool>::*excb)(const ::Ice::Exception&),
-            void (AmiCollector<bool>::*sentcb)(bool)) = Ice::newCallback_Object_ice_isA;
-
-    uut->toIceCallback(factory);
+    uut->toIceCallback();
 
     BOOST_CHECK_EQUAL(0, uut->results);
     BOOST_CHECK_EQUAL(0, uut->exceptions);
     BOOST_CHECK_EQUAL(false, uut->complete);
 
-    uut->resultCallback(true);
+    uut->finished(0);
 
     BOOST_CHECK_EQUAL(1, uut->results);
     BOOST_CHECK_EQUAL(0, uut->exceptions);

commit dbbf73986f0b6e47f0b78acfd86a8e288a063b92
Author: David M. Lee <dlee at digium.com>
Date:   Wed Jan 5 12:51:38 2011 -0600

    First attempt at AmiCollector.
    
    Typing of the callback factory class makes this unpleasant.

diff --git a/AmiCollector/CMakeLists.txt b/AmiCollector/CMakeLists.txt
new file mode 100644
index 0000000..47f2510
--- /dev/null
+++ b/AmiCollector/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(src)
+add_subdirectory(test)
diff --git a/AmiCollector/src/AmiCollector.cpp b/AmiCollector/src/AmiCollector.cpp
new file mode 100644
index 0000000..a5e4797
--- /dev/null
+++ b/AmiCollector/src/AmiCollector.cpp
@@ -0,0 +1,17 @@
+/*
+ * 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 "AmiCollector.h"
diff --git a/AmiCollector/src/AmiCollector.h b/AmiCollector/src/AmiCollector.h
new file mode 100644
index 0000000..b01e74b
--- /dev/null
+++ b/AmiCollector/src/AmiCollector.h
@@ -0,0 +1,154 @@
+/*
+ * 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 <Ice/Object.h>
+#include <Ice/Proxy.h>
+#include <Ice/OutgoingAsync.h>
+#include <IceUtil/Handle.h>
+#include <IceUtil/Shared.h>
+
+namespace AsteriskSCF
+{
+namespace IceUtil
+{
+
+/**
+ * Collects the results for multiple asynchronous responses.  While the vote
+ * counting logic is properly locked and thread safe, it is incumbent upon the
+ * implementor of the <code>process*</code> functions to write those functions
+ * to be thread safe.  Feel free to use mMutex (it's protected) if needed.
+ */
+template<typename T>
+class AmiCollector : public ::IceUtil::Shared
+{
+public:
+    typedef T AsyncResultType;
+    typedef AmiCollector<T> Self;
+
+    AmiCollector(size_t numVotes) : mNumVotes(numVotes)
+    {
+    }
+
+    /**
+     * Creates an Ice CallbackPtr wrapper around this object, for use with AMI.
+     */
+    template<typename CB, typename HN>
+    IceInternal::CallbackBasePtr toIceCallback(CB (*newCallbackFunction)
+        (HN,
+            void (Self::*cb)(T),
+            void (Self::*excb)(const ::Ice::Exception&),
+            void (Self::*sentcb)(bool)))
+    {
+        // 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 (mNumVotes == 0)
+        {
+            processCompletion();
+        }
+        return newCallbackFunction(this,
+            &AmiCollector<AsyncResultType>::resultCallback,
+            &AmiCollector<AsyncResultType>::errorCallback,
+            0 /* sentCallback */);
+    }
+
+    size_t getRemainingVotes() const { return mNumVotes; }
+
+protected:
+    /** Protected dtor prevents creating instances on the stack */
+    ~AmiCollector() {}
+    /**
+     * Called for each response received.
+     */
+    virtual void processResult(AsyncResultType result) = 0;
+    /**
+     * Called for each exception received.
+     */
+    virtual void processException(const Ice::Exception& e) = 0;
+    /**
+     * Called after all the responses or exceptions have been accounted for.
+     */
+    virtual void processCompletion() {}
+
+    /**
+     * AMI result callback.
+     */
+    void resultCallback(AsyncResultType result)
+    {
+        try
+        {
+            processResult(result);
+        }
+        catch(...)
+        {
+            countResponse();
+            throw;
+        }
+        countResponse();
+    }
+
+    /**
+     * AMI exception callback.
+     */
+    void errorCallback(const Ice::Exception& e)
+    {
+        try
+        {
+            processException(e);
+        }
+        catch(...)
+        {
+            countResponse();
+            throw;
+        }
+        countResponse();
+    }
+
+    boost::mutex mMutex;
+private:
+    size_t mNumVotes;
+
+    /**
+     * 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(mNumVotes > 0); // we got more responses than expected
+            if (--mNumVotes == 0)
+            {
+                done = true;
+            }
+        }
+
+        if (done)
+        {
+            processCompletion();
+        }
+    }
+};
+
+} // IceUtil
+} // AsteriskSCF
diff --git a/AmiCollector/src/CMakeLists.txt b/AmiCollector/src/CMakeLists.txt
new file mode 100644
index 0000000..319aea0
--- /dev/null
+++ b/AmiCollector/src/CMakeLists.txt
@@ -0,0 +1,6 @@
+asterisk_scf_component_init(ami-collector CXX)
+
+asterisk_scf_component_add_file(ami-collector AmiCollector.h)
+asterisk_scf_component_add_file(ami-collector AmiCollector.cpp)
+
+asterisk_scf_component_build_library(ami-collector)
diff --git a/AmiCollector/test/AmiCollector-test.cpp b/AmiCollector/test/AmiCollector-test.cpp
new file mode 100644
index 0000000..92f1b1c
--- /dev/null
+++ b/AmiCollector/test/AmiCollector-test.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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 <Ice/Proxy.h>
+#include <boost/test/unit_test.hpp>
+
+#include "AmiCollector.h"
+
+using namespace AsteriskSCF::IceUtil;
+
+namespace
+{
+class TestAmiCollector : public AsteriskSCF::IceUtil::AmiCollector<bool>
+{
+public:
+    explicit TestAmiCollector(size_t n) :
+        AmiCollector<bool>(n),
+        results(0),
+        exceptions(0),
+        complete(false)
+    {}
+    int results;
+    int exceptions;
+    bool complete;
+
+    void resultCallback(AsyncResultType result)
+    {
+        AmiCollector<bool>::resultCallback(result);
+    }
+    void errorCallback(const Ice::Exception& e)
+    {
+        AmiCollector<bool>::errorCallback(e);
+    }
+
+protected:
+    ~TestAmiCollector() {}
+    void processResult(AsyncResultType result)
+    {
+        ++results;
+    }
+    void processException(const Ice::Exception& e)
+    {
+        ++exceptions;
+    }
+    void processCompletion()
+    {
+        BOOST_CHECK_EQUAL(false, complete);
+        complete = true;
+    }
+};
+
+typedef IceUtil::Handle<TestAmiCollector> TestAmiCollectorPtr;
+
+template<typename T>
+Ice::CallbackPtr noCallbackPtr(const IceUtil::Handle<T>& ptr,
+    void (T::*cb)(const int&),
+    void (T::*excb)(const Ice::Exception&),
+    void (T::*sentcb)(bool) = 0)
+{
+    return Ice::CallbackPtr();
+}
+}
+
+BOOST_AUTO_TEST_SUITE(AmiCollectorTest)
+
+BOOST_AUTO_TEST_CASE(test_zero)
+{
+    TestAmiCollectorPtr uut = new TestAmiCollector(0);
+
+    Ice::Callback_Object_ice_isAPtr (*factory)
+        (const IceUtil::Handle<AmiCollector<bool> >& instance,
+            void (AmiCollector<bool>::*cb)(bool),
+            void (AmiCollector<bool>::*excb)(const ::Ice::Exception&),
+            void (AmiCollector<bool>::*sentcb)(bool)) = Ice::newCallback_Object_ice_isA;
+
+    uut->toIceCallback(factory);
+
+    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);
+
+    Ice::Callback_Object_ice_isAPtr (*factory)
+        (const IceUtil::Handle<AmiCollector<bool> >& instance,
+            void (AmiCollector<bool>::*cb)(bool),
+            void (AmiCollector<bool>::*excb)(const ::Ice::Exception&),
+            void (AmiCollector<bool>::*sentcb)(bool)) = Ice::newCallback_Object_ice_isA;
+
+    uut->toIceCallback(factory);
+
+    BOOST_CHECK_EQUAL(0, uut->results);
+    BOOST_CHECK_EQUAL(0, uut->exceptions);
+    BOOST_CHECK_EQUAL(false, uut->complete);
+
+    uut->resultCallback(true);
+
+    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
new file mode 100644
index 0000000..eb59de6
--- /dev/null
+++ b/AmiCollector/test/CMakeLists.txt
@@ -0,0 +1,11 @@
+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 test.cpp)
+
+asterisk_scf_component_add_boost_libraries(ami-collector-test unit_test_framework)
+
+asterisk_scf_component_build_standalone(ami-collector-test)
+
+boost_add_test(ami-collector-test)
diff --git a/AmiCollector/test/test.cpp b/AmiCollector/test/test.cpp
new file mode 100644
index 0000000..5503c6c
--- /dev/null
+++ b/AmiCollector/test/test.cpp
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+#define BOOST_TEST_MODULE Logger-client
+#include <boost/test/unit_test.hpp>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8212b2a..67c5652 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -5,3 +5,4 @@ endif()
 
 add_subdirectory(SmartProxy)
 add_subdirectory(StateReplicator)
+add_subdirectory(AmiCollector)

commit df4537a88e8a9f42b3bb8e1c3030de31ef7a717a
Author: David M. Lee <dlee at digium.com>
Date:   Wed Dec 8 14:59:44 2010 -0600

    Tightened up state replicator's dependencies.

diff --git a/StateReplicator/src/CMakeLists.txt b/StateReplicator/src/CMakeLists.txt
index 1dc097d..3eb7d57 100644
--- a/StateReplicator/src/CMakeLists.txt
+++ b/StateReplicator/src/CMakeLists.txt
@@ -8,12 +8,5 @@ asterisk_scf_component_add_boost_libraries(StateReplicator thread)
 
 asterisk_scf_component_build_library(StateReplicator)
 
-# MACH-O requires libraries for linking libraries
-if(APPLE)
-  target_link_libraries(StateReplicator ${ICE_CXX_LIB_IceUtil})
-  target_link_libraries(StateReplicator ${ICE_CXX_LIB_ZeroCIce})
-endif()
-
-
 asterisk_scf_component_install(StateReplicator LIBRARY lib "State Replicator" statereplicator ARCHIVE DESTINATION lib)
 
diff --git a/StateReplicator/src/StateReplicator.cpp b/StateReplicator/src/StateReplicator.cpp
index 5674a57..a2b6af7 100644
--- a/StateReplicator/src/StateReplicator.cpp
+++ b/StateReplicator/src/StateReplicator.cpp
@@ -14,8 +14,6 @@
  * at the top of the source tree.
  */
 
-#include <IceUtil/UUID.h>
-
 #include "StateReplicator.h"
 
 namespace AsteriskSCF
diff --git a/StateReplicator/src/StateReplicator.h b/StateReplicator/src/StateReplicator.h
index b778aeb..425d2fb 100644
--- a/StateReplicator/src/StateReplicator.h
+++ b/StateReplicator/src/StateReplicator.h
@@ -15,7 +15,8 @@
  */
 #pragma once
 
-#include <Ice/Ice.h>
+#include <Ice/Exception.h>
+#include <Ice/Current.h>
 #include <boost/thread/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
 

commit 252d2c549a9b0e6c0b92e0e65896f93c108a44d7
Author: David M. Lee <dlee at digium.com>
Date:   Wed Dec 8 14:31:27 2010 -0600

    Ice libraries link more sanely now.

diff --git a/SmartProxy/src/CMakeLists.txt b/SmartProxy/src/CMakeLists.txt
index 2d38072..af426fb 100644
--- a/SmartProxy/src/CMakeLists.txt
+++ b/SmartProxy/src/CMakeLists.txt
@@ -15,12 +15,6 @@ include_directories(${logger_dir}/client/src)
 
 asterisk_scf_component_build_library(SmartProxy)
 
-# MACH-O requires libraries for linking libraries
-if(APPLE)
-  target_link_libraries(SmartProxy ${ICE_CXX_LIB_IceUtil})
-  target_link_libraries(SmartProxy ${ICE_CXX_LIB_ZeroCIce})
-endif()
-
 target_link_libraries(SmartProxy logging-client)
 
 asterisk_scf_component_install(SmartProxy LIBRARY lib "Smart Proxy" SmartProxy ARCHIVE DESTINATION lib)

commit f892a8393bee4e04986191f1a214ba6803d4c643
Author: Ken Hunt <ken.hunt at digium.com>
Date:   Tue Dec 7 16:49:18 2010 -0600

    Added required logger target lib for windows build.

diff --git a/SmartProxy/src/CMakeLists.txt b/SmartProxy/src/CMakeLists.txt
index cb7ea20..2d38072 100644
--- a/SmartProxy/src/CMakeLists.txt
+++ b/SmartProxy/src/CMakeLists.txt
@@ -21,5 +21,7 @@ if(APPLE)
   target_link_libraries(SmartProxy ${ICE_CXX_LIB_ZeroCIce})
 endif()
 
+target_link_libraries(SmartProxy logging-client)
+
 asterisk_scf_component_install(SmartProxy LIBRARY lib "Smart Proxy" SmartProxy ARCHIVE DESTINATION lib)
 

commit 92ca85d2d8db6e9bf2817eada1c4a6914fe5523d
Author: Ken Hunt <ken.hunt at digium.com>
Date:   Fri Dec 3 13:07:22 2010 -0600

    Manage boost link options in CMake.

diff --git a/StateReplicator/test/CMakeLists.txt b/StateReplicator/test/CMakeLists.txt
index 00d0337..673a9cd 100644
--- a/StateReplicator/test/CMakeLists.txt
+++ b/StateReplicator/test/CMakeLists.txt
@@ -7,7 +7,7 @@ asterisk_scf_component_add_file(StateReplicatorTest TestStateReplicator.cpp)
 asterisk_scf_component_add_file(StateReplicatorTest SharedTestData.h)
 asterisk_scf_component_add_file(StateReplicatorTest MockStateReplicatorListener.h)
 
-asterisk_scf_component_add_boost_libraries(StateReplicatorTest unit_test_framework thread)
+asterisk_scf_component_add_boost_libraries(StateReplicatorTest unit_test_framework thread date_time)
 
 asterisk_scf_component_build_standalone(StateReplicatorTest)
 asterisk_scf_component_install(StateReplicatorTest RUNTIME bin "StateReplicatorTest Component Test Driver." Test)
diff --git a/StateReplicator/test/TestStateReplicator.cpp b/StateReplicator/test/TestStateReplicator.cpp
index 5cc81a8..4b46e1e 100644
--- a/StateReplicator/test/TestStateReplicator.cpp
+++ b/StateReplicator/test/TestStateReplicator.cpp
@@ -13,7 +13,6 @@
  * the GNU General Public License Version 2. See the LICENSE.txt file
  * at the top of the source tree.
  */
-#define BOOST_TEST_DYN_LINK
 #define BOOST_TEST_MODULE StateReplicatorComponentTestSuite
 #define BOOST_TEST_NO_MAIN
 

commit 91df85017b172327c9464474c5a2224f0927c526
Author: David M. Lee <dlee at digium.com>
Date:   Fri Dec 3 14:05:40 2010 -0600

    Make initializeOnce public.
    
    There are cases where the user of the SmartProxy may want to try to
    safely initialize the proxy, without the ugliness of wrapping the
    operator-> call with a try {} catch block.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index e0443c9..e7b6bc9 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -105,6 +105,25 @@ public:
         return mProxy != 0;
     }
 
+    /**
+     * Initializes this SmartProxy, but only if it hasn't already been
+     * initialized.
+     *
+     * @return True if initialization successful; false if unsuccessful.
+     */
+    bool initializeOnce()
+    {
+        // isInitialized() and initialize() are thread safe.  no need to lock
+        if (isInitialized())
+        {
+            return true;
+        }
+
+        // Try again to initialize.
+        initialize();
+        return isInitialized();
+    }
+
 private:
     /**
      * Initialization. Primarily involves acquring access to specific IceStorm
@@ -157,25 +176,6 @@ private:
         }
     }
 
-    /**
-     * Initializes this SmartProxy, but only if it hasn't already been
-     * initialized.
-     *
-     * @return True if initialization successful; false if unsuccessful.
-     */
-    bool initializeOnce()
-    {
-        // isInitialized() and initialize() are thread safe.  no need to lock
-        if (isInitialized())
-        {
-            return true;
-        }
-
-        // Try again to initialize.
-        initialize();
-        return isInitialized();
-    }
-
     void copy(const SmartProxy &rhs)
     {
         // thread safe

commit 6c28b354ea95d1722f3643320a3d4054913844fb
Author: David M. Lee <dlee at digium.com>
Date:   Thu Dec 2 16:26:28 2010 -0600

    Making SmartProxy thread safe.
    
    See CR-ASTSCF-1.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index 6af5aba..e0443c9 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -18,6 +18,7 @@
 #include <iostream>
 
 #include <Ice/Ice.h>
+#include <IceUtil/Mutex.h>
 
 #include "Core/Discovery/ServiceLocatorIf.h"
 #include "logger.h"
@@ -68,6 +69,7 @@ public:
 
     P& operator->()
     {
+        // everything this calls is thread safe.  no need to lock.
         assert(mServiceLocator && mLocatorParams);
 
         if (!initializeOnce())
@@ -80,6 +82,8 @@ public:
 
     SmartProxy &operator=(const SmartProxy &rhs)
     {
+        // copy is thread safe.  no need to lock.
+
         // Boo to self-assignment
         if (this == &rhs)
         {
@@ -91,11 +95,13 @@ public:
 
     operator void*() const
     {
+        // mProxy itself is thread safe.  no need to lock
         return mProxy ? (void *)1 : 0;
     }
 
     bool isInitialized() const
     {
+        // mProxy itself is thread safe.  no need to lock
         return mProxy != 0;
     }
 
@@ -106,6 +112,9 @@ private:
      */
     void initialize()
     {
+        // thread safe
+        IceUtil::Mutex::Lock myLock(mMutex);
+
         using namespace AsteriskSCF::System::Logging;
         if (!mServiceLocator)
         {
@@ -156,6 +165,7 @@ private:
      */
     bool initializeOnce()
     {
+        // isInitialized() and initialize() are thread safe.  no need to lock
         if (isInitialized())
         {
             return true;
@@ -168,12 +178,18 @@ private:
 
     void copy(const SmartProxy &rhs)
     {
+        // thread safe
+        IceUtil::Mutex::Lock myLock(mMutex);
+        IceUtil::Mutex::Lock rhsLock(rhs.mMutex);
+
         mProxy = rhs.mProxy;
         mServiceLocator = rhs.mServiceLocator;
         mLocatorParams = rhs.mLocatorParams;
         mLogger = rhs.mLogger;
     }
 
+    // we want to lock even const instances, so mMutex must be mutable
+    mutable IceUtil::Mutex mMutex;
     P mProxy;
     AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx mServiceLocator;
     AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr mLocatorParams;

commit cf5c0c056f8b62c126dea4087f4c3003e77d08e7
Author: David M. Lee <dlee at digium.com>
Date:   Thu Dec 2 16:20:47 2010 -0600

    A little const correctness.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index e295bbb..6af5aba 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -94,7 +94,7 @@ public:
         return mProxy ? (void *)1 : 0;
     }
 
-    bool isInitialized()
+    bool isInitialized() const
     {
         return mProxy != 0;
     }

commit 3f5e6b9888e8a75d3846f191c7cc0cc03a1c59b3
Author: David M. Lee <dlee at digium.com>
Date:   Thu Dec 2 15:28:33 2010 -0600

    Added some additional null checks.
    
    See CR-ASTSCF-1.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index 36597f7..e295bbb 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -57,6 +57,12 @@ public:
         AsteriskSCF::System::Logging::Logger const &lg)
         :  mServiceLocator(locator), mLocatorParams(params), mLogger(&lg)
     {
+        using namespace AsteriskSCF::System::Logging;
+        if (!mLocatorParams)
+        {
+            lg(Error) << "Cannot find service with null parameters";
+            throw AsteriskSCF::Core::Discovery::V1::ServiceNotFound();
+        }
         initialize();
     }
 
@@ -108,6 +114,16 @@ private:
             return;
         }
 
+        // all paths to set mServiceLocator also set mLogger.
+        // but just in case things change in the future...
+        assert(mLogger);
+
+        if (!mLocatorParams)
+        {
+            (*mLogger)(Error) << "Cannot find service with null parameters";
+            return;
+        }
+
         try
         {
             // Use the locator to find the Proxy

commit c64f60676cb2cab9f7c94e159a4a3af577e24d1e
Author: David M. Lee <dlee at digium.com>
Date:   Thu Dec 2 15:27:32 2010 -0600

    Removed exception specification.  Old Java habits die hard.
    
    See CR-ASTSCF-1.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index 550425b..36597f7 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -60,7 +60,7 @@ public:
         initialize();
     }
 
-    P& operator->() throw (AsteriskSCF::Core::Discovery::V1::ServiceNotFound)
+    P& operator->()
     {
         assert(mServiceLocator && mLocatorParams);
 

commit 016cc138f828cff40f81a2f45247a3de9351886e
Author: David M. Lee <dlee at digium.com>
Date:   Thu Dec 2 14:50:34 2010 -0600

    Pass Ptr by reference instead of by value.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index 71c5856..550425b 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -53,7 +53,7 @@ public:
 
     SmartProxy(
         const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& locator,
-        AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr params,
+        const AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr& params,
         AsteriskSCF::System::Logging::Logger const &lg)
         :  mServiceLocator(locator), mLocatorParams(params), mLogger(&lg)
     {

commit 9719909659c73691c43007c173a12d193b5927f9
Author: David M. Lee <dlee at digium.com>
Date:   Thu Dec 2 12:53:34 2010 -0600

    mLg -> mLogger
    
    The mLg name was carried over from the use of lg as the Logger name when
    it's a file scoped variable.  But given the scope of this member
    variable, mLogger is more appropriate.
    See CR-ASTSCF-1.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index d141d95..71c5856 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -44,17 +44,18 @@ template <class P>
 class SmartProxy
 {
 public:
-    SmartProxy() : mServiceLocator(0), mLocatorParams(0), mLg(0) {}
+    SmartProxy() : mServiceLocator(0), mLocatorParams(0), mLogger(0) {}
 
     SmartProxy(const SmartProxy &rhs)
     {
         copy(rhs);
     }
 
-    SmartProxy(const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& locator,
+    SmartProxy(
+        const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& locator,
         AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr params,
         AsteriskSCF::System::Logging::Logger const &lg)
-        :  mServiceLocator(locator), mLocatorParams(params), mLg(&lg)
+        :  mServiceLocator(locator), mLocatorParams(params), mLogger(&lg)
     {
         initialize();
     }
@@ -94,7 +95,8 @@ public:
 
 private:
     /**
-     * Initialization. Primarily involves acquring access to specific IceStorm topic.
+     * Initialization. Primarily involves acquring access to specific IceStorm
+     * topic.
      */
     void initialize()
     {
@@ -113,18 +115,20 @@ private:
             mProxy = P::checkedCast(obj);
             if (obj && !mProxy)
             {
-                (*mLg)(Error) << "Object (" << obj->ice_toString() << ") isn't of expected type";
+                (*mLogger)(Error) << "Object (" << obj->ice_toString()
+                                  << ") isn't of expected type";
             }
         }
         catch (const Ice::Exception &e)
         {
-            (*mLg)(Error) << "Exception locating " << mLocatorParams->category << ": " << e.what();
+            (*mLogger)(Error) << "Exception locating "
+                              << mLocatorParams->category << ": " << e.what();
             return;
         }
 
         if (mProxy == 0)
         {
-            (*mLg)(Error) << "Unable to locate " << mLocatorParams->category;
+            (*mLogger)(Error) << "Unable to locate " << mLocatorParams->category;
         }
     }
 
@@ -151,13 +155,13 @@ private:
         mProxy = rhs.mProxy;
         mServiceLocator = rhs.mServiceLocator;
         mLocatorParams = rhs.mLocatorParams;
-        mLg = rhs.mLg;
+        mLogger = rhs.mLogger;
     }
 
     P mProxy;
     AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx mServiceLocator;
     AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr mLocatorParams;
-    AsteriskSCF::System::Logging::Logger const *mLg;
+    AsteriskSCF::System::Logging::Logger const *mLogger;
 };
 
 }; // end SmartProxy

commit f2da511f5e9c516626fb788254ee3c83d4df1a58
Author: David M. Lee <dlee at digium.com>
Date:   Thu Dec 2 12:48:39 2010 -0600

    verifyInitialize -> initializeOnce
    
    Since the function does more than just verify, it needs a more accurate
    name.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index dd0d8bb..d141d95 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -63,7 +63,7 @@ public:
     {
         assert(mServiceLocator && mLocatorParams);
 
-        if (!verifyInitialized())
+        if (!initializeOnce())
         {
             throw AsteriskSCF::Core::Discovery::V1::ServiceNotFound();
         }
@@ -129,9 +129,12 @@ private:
     }
 
     /**
-     * Utiltity to check for initialization state.
+     * Initializes this SmartProxy, but only if it hasn't already been
+     * initialized.
+     *
+     * @return True if initialization successful; false if unsuccessful.
      */
-    bool verifyInitialized()
+    bool initializeOnce()
     {
         if (isInitialized())
         {

commit f5e31dfba81ff92cec22ba81e36ff333afd38fa4
Author: David M. Lee <dlee at digium.com>
Date:   Mon Nov 29 08:54:27 2010 -0600

    Got rid of extra bool to track state.

diff --git a/SmartProxy/src/SmartProxy.h b/SmartProxy/src/SmartProxy.h
index 8e5da1f..dd0d8bb 100644
--- a/SmartProxy/src/SmartProxy.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -44,7 +44,7 @@ template <class P>
 class SmartProxy
 {
 public:
-    SmartProxy() : mServiceLocator(0), mLocatorParams(0), mInitialized(false), mLg(0) {}
+    SmartProxy() : mServiceLocator(0), mLocatorParams(0), mLg(0) {}
 
     SmartProxy(const SmartProxy &rhs)
     {
@@ -54,7 +54,7 @@ public:
     SmartProxy(const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& locator,
         AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr params,
         AsteriskSCF::System::Logging::Logger const &lg)
-        :  mServiceLocator(locator), mLocatorParams(params), mInitialized(false), mLg(&lg)
+        :  mServiceLocator(locator), mLocatorParams(params), mLg(&lg)
     {
         initialize();
     }
@@ -89,7 +89,7 @@ public:
 
     bool isInitialized()
     {
-        return mInitialized;
+        return mProxy != 0;
     }
 
 private:
@@ -126,10 +126,6 @@ private:
         {
             (*mLg)(Error) << "Unable to locate " << mLocatorParams->category;
         }
-        else
-        {
-            mInitialized = true;
-        }
     }
 
     /**
@@ -137,14 +133,14 @@ private:
      */
     bool verifyInitialized()
     {
-        if (mInitialized)
+        if (isInitialized())
         {
             return true;
         }
 
         // Try again to initialize.
         initialize();
-        return mInitialized;
+        return isInitialized();
     }
 
     void copy(const SmartProxy &rhs)
@@ -153,14 +149,12 @@ private:
         mServiceLocator = rhs.mServiceLocator;
         mLocatorParams = rhs.mLocatorParams;
         mLg = rhs.mLg;
-        mInitialized = rhs.mInitialized;
     }
 
     P mProxy;
     AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx mServiceLocator;
     AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr mLocatorParams;
     AsteriskSCF::System::Logging::Logger const *mLg;
-    bool mInitialized;
 };
 
 }; // end SmartProxy

commit 909b2ff2d9b7796c1533718af692fe3cd2d69e01
Author: David M. Lee <dlee at digium.com>
Date:   Mon Nov 22 20:55:14 2010 -0600

    First round of SmartProxy cleanups.
    
    * ProxyWrapper -> SmartProxy
    * Log to Logger instead of cout
    * Throw real exception instead of string

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 79e7361..8212b2a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,5 +3,5 @@ if (integrated_build STREQUAL "true")
 	set(utils_bindir ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
 endif()
 
-add_subdirectory(ProxyWrapper)
+add_subdirectory(SmartProxy)
 add_subdirectory(StateReplicator)
diff --git a/ProxyWrapper/src/CMakeLists.txt b/ProxyWrapper/src/CMakeLists.txt
deleted file mode 100644
index da2461d..0000000
--- a/ProxyWrapper/src/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-# Define the SIP Channel Service component
-
-asterisk_scf_component_init(ProxyWrapper CXX)
-
-asterisk_scf_component_add_slice(ProxyWrapper ServiceLocatorIf)
-asterisk_scf_component_add_file(ProxyWrapper ProxyWrapper.h)
-asterisk_scf_component_add_file(ProxyWrapper ProxyWrapper.cpp)
-asterisk_scf_component_add_boost_libraries(ProxyWrapper core)
-
-asterisk_scf_component_build_library(ProxyWrapper)
-
-# MACH-O requires libraries for linking libraries
-if(APPLE)
-  target_link_libraries(ProxyWrapper ${ICE_CXX_LIB_IceUtil})
-  target_link_libraries(ProxyWrapper ${ICE_CXX_LIB_ZeroCIce})
-endif()
-
-asterisk_scf_component_install(ProxyWrapper LIBRARY lib "Proxy Wrapper" ProxyWrapper ARCHIVE DESTINATION lib)
-
diff --git a/ProxyWrapper/CMakeLists.txt b/SmartProxy/CMakeLists.txt
similarity index 100%
rename from ProxyWrapper/CMakeLists.txt
rename to SmartProxy/CMakeLists.txt
diff --git a/SmartProxy/src/CMakeLists.txt b/SmartProxy/src/CMakeLists.txt
new file mode 100644
index 0000000..cb7ea20
--- /dev/null
+++ b/SmartProxy/src/CMakeLists.txt
@@ -0,0 +1,25 @@
+# Define the SIP Channel Service component
+
+asterisk_scf_component_init(SmartProxy CXX)
+
+asterisk_scf_component_add_slice(SmartProxy ServiceLocatorIf)
+asterisk_scf_component_add_file(SmartProxy SmartProxy.h)
+asterisk_scf_component_add_file(SmartProxy SmartProxy.cpp)
+asterisk_scf_component_add_boost_libraries(SmartProxy core)
+
+if(NOT logger_dir)
+   message(FATAL_ERROR "The logger directory could not be found ${logger_dir}")
+endif()
+include_directories(${logger_dir}/common)
+include_directories(${logger_dir}/client/src)
+
+asterisk_scf_component_build_library(SmartProxy)
+
+# MACH-O requires libraries for linking libraries
+if(APPLE)
+  target_link_libraries(SmartProxy ${ICE_CXX_LIB_IceUtil})
+  target_link_libraries(SmartProxy ${ICE_CXX_LIB_ZeroCIce})
+endif()
+
+asterisk_scf_component_install(SmartProxy LIBRARY lib "Smart Proxy" SmartProxy ARCHIVE DESTINATION lib)
+
diff --git a/ProxyWrapper/src/ProxyWrapper.cpp b/SmartProxy/src/SmartProxy.cpp
similarity index 96%
rename from ProxyWrapper/src/ProxyWrapper.cpp
rename to SmartProxy/src/SmartProxy.cpp
index 875d360..d4e7c45 100644
--- a/ProxyWrapper/src/ProxyWrapper.cpp
+++ b/SmartProxy/src/SmartProxy.cpp
@@ -14,7 +14,7 @@
  * at the top of the source tree.
  */
 
-#include "ProxyWrapper.h"
+#include "SmartProxy.h"
 
 namespace AsteriskSCF
 {
diff --git a/ProxyWrapper/src/ProxyWrapper.h b/SmartProxy/src/SmartProxy.h
similarity index 58%
rename from ProxyWrapper/src/ProxyWrapper.h
rename to SmartProxy/src/SmartProxy.h
index 3439f3f..8e5da1f 100644
--- a/ProxyWrapper/src/ProxyWrapper.h
+++ b/SmartProxy/src/SmartProxy.h
@@ -15,21 +15,23 @@
  */
 #pragma once
 
+#include <iostream>
+
 #include <Ice/Ice.h>
-#include <boost/shared_ptr.hpp>
 
 #include "Core/Discovery/ServiceLocatorIf.h"
+#include "logger.h"
 
 namespace AsteriskSCF
 {
-namespace ProxyWrapper
+namespace SmartProxy
 {
 
 /**
  * A wrapper for an Ice Proxy.
  * The Template parameter P is the proxy we're wrapping
  *
- * The main feature of using a proxy wrapper at this stage is that
+ * The main feature of using a smart proxy at this stage is that
  * it provides the ability to detect if we could find a given proxy
  * at initialization. If we did not, then the first time we try to
  * invoke a proxy operation, then we will attempt to acquire a proxy
@@ -39,43 +41,44 @@ namespace ProxyWrapper
  * more general purpose.
  */
 template <class P>
-class ProxyWrapper
+class SmartProxy
 {
 public:
-    ProxyWrapper() : mServiceLocator(0), mLocatorParams(0), mInitialized(false) {}
+    SmartProxy() : mServiceLocator(0), mLocatorParams(0), mInitialized(false), mLg(0) {}
 
-    ProxyWrapper(const ProxyWrapper &pw)
+    SmartProxy(const SmartProxy &rhs)
     {
-        copy(pw);
+        copy(rhs);
     }
 
-    ProxyWrapper(const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& locator,
-        AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr params)
-        :  mServiceLocator(locator), mLocatorParams(params), mInitialized(false)
+    SmartProxy(const AsteriskSCF::Core::Discovery::V1::ServiceLocatorPrx& locator,
+        AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr params,
+        AsteriskSCF::System::Logging::Logger const &lg)
+        :  mServiceLocator(locator), mLocatorParams(params), mInitialized(false), mLg(&lg)
     {
         initialize();
     }
 
-    P& operator->()
+    P& operator->() throw (AsteriskSCF::Core::Discovery::V1::ServiceNotFound)
     {
         assert(mServiceLocator && mLocatorParams);
 
         if (!verifyInitialized())
         {
-            throw "No access to Proxy";
+            throw AsteriskSCF::Core::Discovery::V1::ServiceNotFound();
         }
 
         return mProxy;
     }
 
-    ProxyWrapper operator=(const ProxyWrapper &pw)
+    SmartProxy &operator=(const SmartProxy &rhs)
     {
         // Boo to self-assignment
-        if (this == &pw)
+        if (this == &rhs)
         {
             return *this;
         }
-        copy(pw);
+        copy(rhs);
         return *this;
     }
 
@@ -95,24 +98,38 @@ private:
      */
     void initialize()
     {
+        using namespace AsteriskSCF::System::Logging;
+        if (!mServiceLocator)
+        {
+            // uninitialized; probably no logger setup yet, either
+            std::clog << "Missing ServiceLocator proxy.  Cannot initialize.\n";
+            return;
+        }
+
         try
         {
             // Use the locator to find the Proxy
-            Ice::ObjectPrx bridgeManagerObject = mServiceLocator->locate(mLocatorParams);
-            mProxy = P::checkedCast(bridgeManagerObject);
+            Ice::ObjectPrx obj = mServiceLocator->locate(mLocatorParams);
+            mProxy = P::checkedCast(obj);
+            if (obj && !mProxy)
+            {
+                (*mLg)(Error) << "Object (" << obj->ice_toString() << ") isn't of expected type";
+            }
         }
         catch (const Ice::Exception &e)
         {
... 4750 lines suppressed ...


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



More information about the asterisk-scf-commits mailing list