[asterisk-scf-commits] asterisk-scf/integration/ice-util-cpp.git branch "move-bridge-util-functions" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Wed Apr 27 13:32:08 CDT 2011


branch "move-bridge-util-functions" has been updated
       via  ac5cf0b1e54e43fa677af49c08a8d75067cff116 (commit)
       via  652741a0e5cc85baa21ec508b7fd3cf118446ec4 (commit)
       via  fd811e3d47f7b1ac5fb9532490a7c094ce22bf74 (commit)
       via  11079f2e12fd9eb6cd597ed8c7cb85ca291110f4 (commit)
       via  6626b684faccb6679dac6698954f889afde6bb8d (commit)
       via  a7721c5453e659ac841b63cbfe5ef76cdbe9ecba (commit)
       via  e8001bdd50f0847b886fa85544e5be4ce85292c5 (commit)
       via  ff03bb063c8737d5ed3dbb31372269be9080fb1c (commit)
       via  2d86b6396e8ae2eee499da8995994e887701d93d (commit)
       via  cf2f9b9ada6a587a0cb2926c6c5d594eba26be76 (commit)
       via  d44d47af554d41e1326ae6bbf03fca6cc93cdd32 (commit)
      from  853b36ba80ed5692b9f4b2acbfaa22f5f65cff2d (commit)

Summary of changes:
 AmiCollector/test/CMakeLists.txt                   |    2 +-
 AmiCollector/test/TestAmiCollector.h               |    4 +-
 CMakeLists.txt                                     |    5 +-
 SmartProxy/include/AsteriskSCF/SmartProxy.h        |   51 ++--
 .../include/AsteriskSCF/StateReplicator.h          |    2 +-
 StateReplicator/test/CMakeLists.txt                |    2 +-
 TestFixture/CMakeLists.txt                         |   16 +
 TestFixture/include/AsteriskSCF/IceBoxBoostTest.h  |   85 ++++++
 .../test.cpp => TestFixture/src/TestFixture.cpp    |    5 +-
 config/test_ice_cpp_utility.conf                   |   20 ++
 include/AsteriskSCF/Helpers/PropertyHelper.h       |  180 ++++++++++++
 include/AsteriskSCF/Helpers/ProxyHelper.h          |  194 +++++++++++++
 include/AsteriskSCF/Helpers/Retry.h                |   82 ++++++
 .../test.cpp => include/AsteriskSCF/IceUtility.h   |   10 +-
 include/AsteriskSCF/Listener/ListenerManager.h     |  295 ++++++++++++++++++++
 .../LocatorRegistrationWrapper.h                   |  166 +++++++++++
 test/CMakeLists.txt                                |   19 ++
 .../ListenerManager/ListenerManagerTests.cpp       |   13 +-
 test/PropertyHelper/PropertyHelperTest.cpp         |   96 +++++++
 .../PropertyHelper/PropertyHelperTest.h            |   21 +-
 test/PropertyHelper/main.cpp                       |   18 ++
 test/ProxyHelper/ProxyHelperTests.cpp              |  140 +++++++++
 .../ProxyHelper/ProxyHelperTests.h                 |   26 ++-
 .../ProxyHelper/SimpleIf.ice                       |   20 +-
 test/UtilityTests.cpp                              |  134 +++++++++
 25 files changed, 1537 insertions(+), 69 deletions(-)
 create mode 100644 TestFixture/CMakeLists.txt
 create mode 100644 TestFixture/include/AsteriskSCF/IceBoxBoostTest.h
 copy AmiCollector/test/test.cpp => TestFixture/src/TestFixture.cpp (86%)
 create mode 100644 config/test_ice_cpp_utility.conf
 create mode 100644 include/AsteriskSCF/Helpers/PropertyHelper.h
 create mode 100644 include/AsteriskSCF/Helpers/ProxyHelper.h
 create mode 100644 include/AsteriskSCF/Helpers/Retry.h
 copy AmiCollector/test/test.cpp => include/AsteriskSCF/IceUtility.h (72%)
 create mode 100644 include/AsteriskSCF/Listener/ListenerManager.h
 create mode 100644 include/AsteriskSCF/LocatorRegistration/LocatorRegistrationWrapper.h
 create mode 100644 test/CMakeLists.txt
 copy AmiCollector/test/test.cpp => test/ListenerManager/ListenerManagerTests.cpp (74%)
 create mode 100644 test/PropertyHelper/PropertyHelperTest.cpp
 copy SmartProxy/src/SmartProxy.cpp => test/PropertyHelper/PropertyHelperTest.h (56%)
 create mode 100644 test/PropertyHelper/main.cpp
 create mode 100644 test/ProxyHelper/ProxyHelperTests.cpp
 copy SmartProxy/src/SmartProxy.cpp => test/ProxyHelper/ProxyHelperTests.h (51%)
 copy SmartProxy/src/SmartProxy.cpp => test/ProxyHelper/SimpleIf.ice (69%)
 create mode 100644 test/UtilityTests.cpp


- Log -----------------------------------------------------------------
commit ac5cf0b1e54e43fa677af49c08a8d75067cff116
Author: Brent Eagles <beagles at digium.com>
Date:   Mon Apr 25 13:58:42 2011 -0230

    Adding several utility classes to ice-cpp-util, borrowed from the bridging service code.
    There are some tests, but probably could be more exhaustive. NOTE: These utility classes
    were added with a slightly different directory structure than the existing contents of
    ice-util-cpp. This is in response to a discussion on IRC about choosing a more consolidated
    layout so all of the utility classes would be gathered into a compilation/install target and
    a test target.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d49205b..7ae34a2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,3 +8,4 @@ add_subdirectory(SmartProxy)
 add_subdirectory(StateReplicator)
 add_subdirectory(AmiCollector)
 add_subdirectory(TestFixture)
+add_subdirectory(test)
diff --git a/SmartProxy/include/AsteriskSCF/SmartProxy.h b/SmartProxy/include/AsteriskSCF/SmartProxy.h
index 3ee09ce..ce59be7 100644
--- a/SmartProxy/include/AsteriskSCF/SmartProxy.h
+++ b/SmartProxy/include/AsteriskSCF/SmartProxy.h
@@ -154,6 +154,7 @@ public:
                               << mLocatorParams->category << ": " << e.what();
             return 0;
         }
+        catch (const 
 
         if (mProxy == 0)
         {
diff --git a/config/test_ice_cpp_utility.conf b/config/test_ice_cpp_utility.conf
new file mode 100644
index 0000000..9941899
--- /dev/null
+++ b/config/test_ice_cpp_utility.conf
@@ -0,0 +1,20 @@
+################################################################################
+# Configuration file for use with the bridging component's test driver.
+#
+#
+# General configuration
+#
+# We turn off all collocation optimization by default to avoid issues with any services
+# that might have trouble due to AMI/AMD usage.
+#
+Ice.Default.CollocationOptimized=0
+
+#
+# We use a single file for configuration.
+#
+IceBox.InheritProperties=1
+IceBox.ServiceManager.Endpoints=default -p 56000
+IceBox.ServiceManager.ThreadPool.Size=4
+IceBoxManager.Proxy=IceBox/ServiceManager:default -p 56000
+
+IceBox.Service.ProxyHelper=ice_cpp_utility_tests:create
\ No newline at end of file
diff --git a/include/AsteriskSCF/Helpers/PropertyHelper.h b/include/AsteriskSCF/Helpers/PropertyHelper.h
index 696bf75..6a84e74 100644
--- a/include/AsteriskSCF/Helpers/PropertyHelper.h
+++ b/include/AsteriskSCF/Helpers/PropertyHelper.h
@@ -33,9 +33,11 @@ namespace AsteriskSCF
  * any properties if they already exist.
  *
  **/
-inline void propGetSet(const Ice::PropertiesPtr& p, const std::string& propertyName, const std::string& value)
+inline std::string propGetSet(const Ice::PropertiesPtr& p, const std::string& propertyName, const std::string& value)
 {
-    p->setProperty(propertyName, p->getPropertyWithDefault(propertyName, value));
+    std::string result = p->getPropertyWithDefault(propertyName, value);
+    p->setProperty(propertyName, result);
+    return result;
 }
 
 /**
@@ -117,6 +119,11 @@ public:
         return mData->mArguments;
     }
 
+    /**
+     *
+     * Copying is allowed and so should assignment.
+     *
+     */
     StringVectorAsArgs& operator=(const StringVectorAsArgs& rhs)
     {
         if (this == &rhs)
@@ -144,7 +151,7 @@ private:
                 mArgv.push_back(i->c_str());
             }
             mArgv.push_back(static_cast<const char*>(0));
-            mArgc = mArgv.size() -1;
+            mArgc = static_cast<int>(mArgv.size()) -1;
         }
     };
 
@@ -165,7 +172,7 @@ private:
 };
 
 template<>
-void StringVectorAsArgs::copyV(const std::vector<std::string>& p, std::vector<std::string>& dest)
+inline void StringVectorAsArgs::copyV(const std::vector<std::string>& p, std::vector<std::string>& dest)
 {
     dest = p;
 }
diff --git a/include/AsteriskSCF/Helpers/ProxyHelper.h b/include/AsteriskSCF/Helpers/ProxyHelper.h
index 8d7153c..9b98032 100644
--- a/include/AsteriskSCF/Helpers/ProxyHelper.h
+++ b/include/AsteriskSCF/Helpers/ProxyHelper.h
@@ -17,8 +17,14 @@
 #pragma once
 
 #include <assert.h>
-#include <Ice/Communicator.h>
+#include <Ice/Ice.h>
 
+//
+// GENERAL NOTE:
+// While these helpers can certainly be used in an application, they are most useful when writing
+// tests which usually include several repetitive instantiations of servants, proxies, etc.
+// Some of this becomes far less valuable when "auto" is used.
+//
 namespace AsteriskSCF
 {
 /**
@@ -28,16 +34,20 @@ namespace AsteriskSCF
  * the caller to control whether a checked or unchecked cast is performed to downcast the proxy object (remember: a
  * checked cast results in a remote procedure call in this case, the unchecked cast does not).
  *
+ * Note: as function templates don't allow default template parameters, this isn't as pretty as it could be. You have
+ * to specify both the type of the proxy and the casting policy either through a template type argument or through
+ * a parameter.
+ *
  **/
 
 /**
  * Policy for performing checked casts.
  */
-template <class T>
-CheckedCastPolicy
+template <typename T>
+class Checked
 {
 public:
-    T cast(const Ice::ObjectPrx& proxy)
+    T cast(const Ice::ObjectPrx& proxy) const
     {
         return T::checkedCast(proxy);
     }
@@ -46,11 +56,11 @@ public:
 /**
  * Policy for performing unchecked casts.
  */
-template <class T>
-UncheckedCastPolicy
+template <typename T>
+class Unchecked
 {
 public:
-    T cast(const Ice::ObjectPrx& proxy)
+    T cast(const Ice::ObjectPrx& proxy) const
     {
         return T::uncheckedCast(proxy);
     }
@@ -70,13 +80,115 @@ public:
  * @returns An initialized proxy handle of the required type.
  *
  **/
-template <class T, class P = CheckedCastPolicy<T> >
-T getProxy(const Ice::CommunicatorPtr& comm, const std::string& property, T& typedParam = T(), const P& policy = P())
+template <class T, template<class T> class P>
+T getProxy(const Ice::CommunicatorPtr& comm, const std::string& property, T& typedParam = T(),
+        const P<T>& policy = P<T>())
 {
     assert(comm);
     assert(!property.empty());
-    typedParam =  P.cast(comm->propertyToProxy(property));
+    typedParam = policy.cast(comm->propertyToProxy(property));
     return typedParam;
 }
 
+/**
+ *
+ * The addServant helper is a little like the getProxy helper. However, instead of pulling a proxy out
+ * of a communicator's configuration, this helper adds a servant to an object adapter and returns
+ * a proxy of the correct type.
+ *
+ **/
+template <class T>
+T addServant(const Ice::ObjectAdapterPtr& adapter, const Ice::ObjectPtr& servant, const Ice::Identity& t, T& proxy = T())
+{
+    proxy = T::uncheckedCast(adapter->add(servant, t));
+    return proxy;
+}
+
+/**
+ * Overload for those folks that specify a string for an id.
+ **/
+template <class T>
+T addServant(const Ice::ObjectAdapterPtr& adapter, const Ice::ObjectPtr& servant, const std::string& s, T& proxy = T())
+{
+    return addServant(adapter, servant, adapter->getCommunicator()->stringToIdentity(s), proxy);
+}
+
+//
+// The UUID variant is conspicuously absent for the moment. The signature of such a method would be very similar to
+// those above except it would be missing and ID of some kind. I'm concerned that it would get used accidentally.
+//
+
+/**
+ *
+ * A trivial little helper template that attempts to get a oneway proxy, but "rollsback" to the original
+ * proxy if the proxy's endpoints don't allow oneways. OF course, if the caller absolutely requires a
+ * request be over a oneway, then this template *SHOULD NOT* be used.
+ *
+ **/
+template <class PrxType>
+PrxType tryOneWay(const PrxType& orig)
+{
+    try
+    {
+        return PrxType::uncheckedCast(orig->ice_oneway());
+    }
+    catch (const Ice::NoEndpointException&)
+    {
+    }
+    return orig;
+}
+
+/**
+ *
+ * A predicate functor for testing on proxy identity. Handy when searching a collection with std::find().
+ *
+ **/
+template <class T>
+class IdentityComparePredicate : public std::unary_function<T, bool>
+{
+public:
+    IdentityComparePredicate(const T& example) :
+        mExample(example)
+    {
+    }
+
+    bool operator()(const T& toTest)
+    {
+        if (toTest == 0)
+        {
+            return mExample == 0;
+        }
+        if (mExample == 0)
+        {
+            return false;
+        }
+        return (mExample->ice_getIdentity() == toTest->ice_getIdentity());
+    }
+
+    template <class V> 
+    bool operator()(const V& toTest)
+    {
+        if (toTest == 0)
+        {
+            return mExample == 0;
+        }
+        if (mExample == 0)
+        {
+            return false;
+        }
+        return (mExample->ice_getIdentity() == toTest->ice_getIdentity());
+    }
+private:
+    T mExample;
+};
+
+inline std::string objectId(const Ice::Current& current)
+{
+    if (current.adapter)
+    {
+        return current.adapter->getCommunicator()->identityToString(current.id);
+    }
+    return "(unknown)";
+}
+
 }; /* End of namespace AsteriskSCF */
diff --git a/include/AsteriskSCF/Helpers/Retry.h b/include/AsteriskSCF/Helpers/Retry.h
new file mode 100644
index 0000000..3d89bfb
--- /dev/null
+++ b/include/AsteriskSCF/Helpers/Retry.h
@@ -0,0 +1,82 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2011, 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 <Ice/Ice.h>
+#include <IceUtil/Thread.h>
+
+namespace AsteriskSCF
+{
+
+/**
+ *
+ * A simple helper class for implementing retry logic when dealing with remote procedure calls.
+ *
+ */ 
+class RetryPolicy
+{
+public:
+    /**
+     * The constructor for those that want to specify intervals in milliseconds.
+     */
+    RetryPolicy(size_t maxRetries, size_t intervalInMilliseconds) :
+        mMaxRetries(maxRetries),
+        mRetryInterval(IceUtil::Time::milliSeconds(intervalInMilliseconds)),
+        mCounter(0)
+    {
+    }
+
+    /**
+     * The constructor for those that want to specify intervals in whatever
+     * unit they like so long as it is converted to IceUtil::Time.
+     **/
+    RetryPolicy(size_t maxRetries, const IceUtil::Time& interval) :
+        mMaxRetries(maxRetries),
+        mRetryInterval(interval),
+        mCounter(0)
+    {
+    }
+
+    /**
+     * Check to see if we've exceed the specified number of retries.
+     *
+     * @returns true if there are attempts left.
+     **/
+    bool canRetry()
+    {
+        return mCounter < mMaxRetries;
+    }
+
+    /**
+     * Sleep for the configured interval.
+     *
+     * @returns true if there are attempts left.
+     **/
+    bool retry()
+    {
+        IceUtil::ThreadControl::sleep(mRetryInterval);
+        ++mCounter;
+        return canRetry();
+    }
+
+private:
+    size_t mMaxRetries;
+    IceUtil::Time mRetryInterval;
+    size_t mCounter;
+};
+
+
+} /* End of namespace AsteriskSCF */
diff --git a/include/AsteriskSCF/LocatorRegistration/LocatorRegistrationWrapper.h b/include/AsteriskSCF/LocatorRegistration/LocatorRegistrationWrapper.h
new file mode 100644
index 0000000..824ca15
--- /dev/null
+++ b/include/AsteriskSCF/LocatorRegistration/LocatorRegistrationWrapper.h
@@ -0,0 +1,166 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-2011, 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 <Ice/Ice.h>
+#include <IceUtil/Thread.h>
+#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
+#include <string>
+
+namespace AsteriskSCF
+{
+
+/**
+ * 
+ * Helper template for services that need to be registered with the locator service. If the service may not
+ * immediately available, the RegisterThread can be used to continue to try and register the service.
+ *
+ * TODO: It might be handy to add some "termination conditions" so it doesn't simply wait forever.
+ *
+ **/
+template <class T>   
+class LocatorRegistrationWrapper : public IceUtil::Shared
+{
+public:
+    LocatorRegistrationWrapper(const Ice::CommunicatorPtr& communicator, const std::string& proxyString,
+            const T& service, const std::string& name,
+            const AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr& params) :
+        mCommunicator(communicator),
+        mProxyString(proxyString),
+        mService(service),
+        mName(name),
+        mParameters(params)
+    {
+    }
+
+    /**
+     * The main registration function. There is *no* exception handling, so the caller must be prepared
+     * to handle whatever might be thrown.
+     **/ 
+    bool registerService()
+    {
+        AsteriskSCF::Core::Discovery::V1::ServiceLocatorManagementPrx management =
+              AsteriskSCF::Core::Discovery::V1::ServiceLocatorManagementPrx::checkedCast(
+                  mCommunicator->stringToProxy(mProxyString));
+        if(management)
+        {
+            IceUtil::Mutex::Lock lock(mLock);
+            mServiceManagement = 
+                AsteriskSCF::Core::Discovery::V1::ServiceManagementPrx::uncheckedCast(
+                    management->addService(mService, mName));
+            if(mServiceManagement)
+            {
+                mServiceManagement->addLocatorParams(mParameters, "");
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Unregister! Note that the destructor for this object does not automatically unregister. This is
+     * because this class is intended as a helper, not an RAII type of object to manage the registration.
+     * It would be easy enough for a developer to derive from an instance of this class and add that
+     * functionality if desired.
+     **/
+    void unregister()
+    {
+        {
+            IceUtil::Mutex::Lock lock(mLock);
+            if(!mServiceManagement)
+            {
+                return;
+            }
+        }
+        mServiceManagement->unregister();
+    }
+
+private:
+
+    //
+    // This template doesn't use boost locking simply because it already has a physical dependency
+    // to Ice runtime, so avoiding adding a second seemed reasonable.
+    //
+    IceUtil::Mutex mLock;
+    Ice::CommunicatorPtr mCommunicator;
+    std::string mProxyString;
+    T mService;
+    std::string mName;
+    AsteriskSCF::Core::Discovery::V1::ServiceLocatorParamsPtr mParameters;
+    AsteriskSCF::Core::Discovery::V1::ServiceManagementPrx mServiceManagement;
+};
+
+/**
+* This thread takes care of registering the bridge if the service discovery components are unavailable during
+ * startup.
+ **/
+template <class T>
+class RegisterThread : public IceUtil::Thread
+{
+public:
+    RegisterThread(const IceUtil::Handle<LocatorRegistrationWrapper<T> >& registration,
+            const IceUtil::Time& retryInterval) :
+        mRegistration(registration),
+        mRetryInterval(retryInterval),
+        mStopped(false)
+    {
+    }
+
+    RegisterThread(const IceUtil::Handle<LocatorRegistrationWrapper<T> >& registration) :
+        mRegistration(registration),
+        mRetryInterval(IceUtil::Time::seconds(15)),
+        mStopped(false)
+    {
+    }
+
+    void run()
+    {
+        bool result = false;
+        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+        do
+        {
+            mMonitor.timedWait(mRetryInterval);
+            if(mStopped)
+            {
+                break;
+            }
+            try
+            {
+                result = mRegistration->registerService();
+            }
+            catch(const Ice::Exception&)
+            {
+            }
+        }
+        while(result == false);
+    }
+
+    void stop()
+    {
+        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+        mStopped = true;
+        mMonitor.notify();
+    }
+
+private:
+    IceUtil::Monitor<IceUtil::Mutex> mMonitor;
+    IceUtil::Handle<LocatorRegistrationWrapper<T> > mRegistration;
+    IceUtil::Time mRetryInterval;
+    bool mStopped;
+};
+
+
+} /* End of namespace AsteriskSCF */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 0000000..757ff94
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,19 @@
+asterisk_scf_slice_include_directories(${API_SLICE_DIR})
+asterisk_scf_component_init(ice_cpp_utility_tests CXX)
+include_directories("../include")
+asterisk_scf_component_add_slice(ice_cpp_utility_tests ./ProxyHelper/SimpleIf.ice)
+asterisk_scf_component_add_file(ice_cpp_utility_tests ./LocatorRegistration/LocatorRegistrationTest.cpp)
+asterisk_scf_component_add_file(ice_cpp_utility_tests ./LocatorRegistration/LocatorRegistrationTest.h)
+asterisk_scf_component_add_file(ice_cpp_utility_tests ./PropertyHelper/PropertyHelperTest.cpp)
+asterisk_scf_component_add_file(ice_cpp_utility_tests ./PropertyHelper/PropertyHelperTest.h)
+asterisk_scf_component_add_file(ice_cpp_utility_tests ./ProxyHelper/ProxyHelperTests.cpp)
+asterisk_scf_component_add_file(ice_cpp_utility_tests ./ProxyHelper/ProxyHelperTests.h)
+asterisk_scf_component_add_file(ice_cpp_utility_tests UtilityTests.cpp)
+
+asterisk_scf_component_add_ice_libraries(ice_cpp_utility_tests IceBox)
+asterisk_scf_component_add_boost_libraries(ice_cpp_utility_tests unit_test_framework date_time thread)
+
+include_directories(${API_INCLUDE_DIR})
+asterisk_scf_component_build_icebox(ice_cpp_utility_tests)
+target_link_libraries(ice_cpp_utility_tests asterisk-scf-api)
+
diff --git a/test/PropertyHelper/PropertyHelperTest.cpp b/test/PropertyHelper/PropertyHelperTest.cpp
index b2bc8d8..fa1e735 100644
--- a/test/PropertyHelper/PropertyHelperTest.cpp
+++ b/test/PropertyHelper/PropertyHelperTest.cpp
@@ -13,18 +13,16 @@
  * the GNU General Public License Version 2. See the LICENSE.txt file
  * at the top of the source tree.
  */
-#define BOOST_TEST_DYN_LINK
 
+#include <Ice/Properties.h>
+#include <Ice/Initialize.h>
 #include <AsteriskSCF/Helpers/PropertyHelper.h>
 #include <boost/lexical_cast.hpp>
 #include <boost/test/unit_test.hpp>
 #include <string>
 #include <vector>
 
-extern "C"
-{
-    void runPropertyHelperTest();
-}
+#include "PropertyHelperTest.h"
 
 namespace AsteriskSCF
 {
@@ -39,7 +37,7 @@ std::string convertToString(const int& t)
 
 using namespace AsteriskSCF;
 
-void testContents(StringVectorAsArgs& t)
+static void testContents(StringVectorAsArgs& t)
 {
     BOOST_REQUIRE(t.argc() == 3);
     BOOST_CHECK(strcmp(t.argv()[0], "1") == 0);
@@ -52,7 +50,7 @@ void testContents(StringVectorAsArgs& t)
     BOOST_CHECK(v[2] == "2");
 }
 
-void runPropertyHelperTest()
+static void runPropertyHelperTest()
 {
     //
     // Simple check of the specialization.
@@ -79,5 +77,20 @@ void runPropertyHelperTest()
 
     defaultConstructor = defaultConstructor;
     testContents(defaultConstructor);
+
+    Ice::PropertiesPtr p = Ice::createProperties();
+    BOOST_REQUIRE(p);
+    std::string result = p->getProperty("test.property");
+    BOOST_CHECK(result.empty());
+    result = propGetSet(p, "test.property", "1");
+    BOOST_CHECK(result == "1");
+    result = p->getProperty("test.property");
+    BOOST_CHECK(result == "1");
 }
+using namespace boost::unit_test;
 
+AsteriskSCF::PropertyHelperTests::PropertyHelperTestSuite::PropertyHelperTestSuite(const Ice::CommunicatorPtr&)
+{
+    framework::master_test_suite().
+        add(BOOST_TEST_CASE(runPropertyHelperTest));
+}
diff --git a/test/ProxyHelper/ProxyHelperTests.cpp b/test/PropertyHelper/PropertyHelperTest.h
similarity index 52%
copy from test/ProxyHelper/ProxyHelperTests.cpp
copy to test/PropertyHelper/PropertyHelperTest.h
index 6b64e85..364ee0c 100644
--- a/test/ProxyHelper/ProxyHelperTests.cpp
+++ b/test/PropertyHelper/PropertyHelperTest.h
@@ -14,36 +14,23 @@
  * at the top of the source tree.
  */
 
-#include <AsteriskSCF/Helpers/PropertyHelper.h>
-#include <AsteriskSCF/Helpers/ProxyHelper.h>
-#include <AsteriskSCF/Testing/IceBoxBoostTest.h>
+#pragma once
+
+#include <Ice/Ice.h>
 
 namespace AsteriskSCF
 {
-namespace ProxyHelperTests
+namespace PropertyHelperTests
 {
 
-class Test : public IceBoxTest
+class PropertyHelperTestSuite
 {
 public:
-    Test()
-    {
-    }
+    /**
+     * Registers the test suite with the global test suite. There isn't anything else that needs to be done.
+     **/
+    PropertyHelperTestSuite(const Ice::CommunicatorPtr& comm);
 };
 
-//
-// Tests for the ProxyHelper facilities.
-//
-static bool init_unit_test()
-{
-    
-}
-
-
-}; /* End of namespace ProxyHelperTests */
-}; /* End of namespace AsteriskSCF */
-
-ASTERISK_SCF_ICEBOX_EXPORT IceBox::Service* create(Ice::CommunicatorPtr communicator)
-{
-    return new AsteriskSCF::ProxyHelperTests::Test;
-}
+} /* End of namespace IceUtilCppTests */
+} /* End of namespace AsteriskSCF */
diff --git a/test/PropertyHelper/main.cpp b/test/PropertyHelper/main.cpp
index ecc1c36..f50d5ec 100644
--- a/test/PropertyHelper/main.cpp
+++ b/test/PropertyHelper/main.cpp
@@ -7,6 +7,11 @@ using namespace std;
 
 extern "C" void runPropertyHelperTest();
 
+//
+// Simple command line driver to run these tests with a limited amount of hassle while they are
+// being developed. (Will be removed when they tests are integrated into a proper test module.
+//
+
 BOOST_AUTO_TEST_CASE( runTest )
 {
     runPropertyHelperTest();
diff --git a/test/ProxyHelper/ProxyHelperTests.cpp b/test/ProxyHelper/ProxyHelperTests.cpp
index 6b64e85..3180a64 100644
--- a/test/ProxyHelper/ProxyHelperTests.cpp
+++ b/test/ProxyHelper/ProxyHelperTests.cpp
@@ -14,36 +14,127 @@
  * at the top of the source tree.
  */
 
+#include <Ice/Ice.h>
+#include <IceBox/IceBox.h>
+#include <IceUtil/Thread.h>
+
 #include <AsteriskSCF/Helpers/PropertyHelper.h>
 #include <AsteriskSCF/Helpers/ProxyHelper.h>
-#include <AsteriskSCF/Testing/IceBoxBoostTest.h>
+#include "ProxyHelperTests.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/bind.hpp>
+#include <boost/test/debug.hpp>
+
+#include "SimpleIf.h"
+
+#include <vector>
+#include <string>
+
+using namespace std;
+using namespace boost::unit_test;
+
+//
+// Barebones test driver while I pull the rest of related code in and reorganize.
+//
 
 namespace AsteriskSCF
 {
 namespace ProxyHelperTests
 {
 
-class Test : public IceBoxTest
+class SimpleTestObjImpl : public SimpleTestIntf
 {
 public:
-    Test()
+    void hiThere(const Ice::Current& current)
     {
+        std::string t = objectId(current);
+        BOOST_CHECK(t == "anotherSimplObj" || t == "simpleObj");
     }
 };
 
-//
-// Tests for the ProxyHelper facilities.
-//
-static bool init_unit_test()
+class TestRunner
 {
-    
-}
+public:
+    TestRunner(const Ice::CommunicatorPtr& c):
+        mCommunicator(c)
+    {
+    }
+
+    void run()
+    {
+        propGetSet(mCommunicator->getProperties(), "TestAdapter.Endpoints", "default -p 55555");
+        propGetSet(mCommunicator->getProperties(), "TestObj.Proxy", "simpleObj:default -p 55555");
+        Ice::ObjectAdapterPtr adapter = mCommunicator->createObjectAdapter("TestAdapter");
 
+        SimpleTestIntfPtr testObj(new SimpleTestObjImpl);
+        SimpleTestIntfPrx o =
+            addServant<SimpleTestIntfPrx>(adapter, testObj, mCommunicator->stringToIdentity("simpleObj"));
+        SimpleTestIntfPrx secondObj =
+            addServant<SimpleTestIntfPrx>(adapter, testObj, "anotherSimplObj");
+        adapter->activate();
+        try
+        {
+            o->hiThere();
+            BOOST_CHECK(true);
+        }
+        catch (const Ice::SocketException&)
+        {
+            BOOST_CHECK(false);
+        }
+        try
+        {
+            secondObj->hiThere();
+            BOOST_CHECK(true);
+        }
+        catch (const Ice::SocketException&)
+        {
+            BOOST_CHECK(false);
+        }
+        
+        o = getProxy<SimpleTestIntfPrx, Checked>(mCommunicator, "TestObj.Proxy");
+        BOOST_CHECK(o);
+        o = 0;
+        o =  getProxy<SimpleTestIntfPrx, Unchecked>(mCommunicator, "TestObj.Proxy");
+        try
+        {
+            o->hiThere();
+            BOOST_CHECK(true);
+        }
+        catch (const Ice::SocketException&)
+        {
+            BOOST_CHECK(false);
+        }
+        try
+        {
+            tryOneWay(o)->hiThere();
+            BOOST_CHECK(true);
+        }
+        catch (const Ice::SocketException&)
+        {
+            BOOST_CHECK(false);
+        }
+        IdentityComparePredicate<SimpleTestIntfPrx> pred(o);
+        BOOST_CHECK(!pred(secondObj));
+        BOOST_CHECK(pred(getProxy<SimpleTestIntfPrx, Checked>(mCommunicator, "TestObj.Proxy")));
+        Ice::ObjectPrx bareObj = mCommunicator->propertyToProxy("TestObj.Proxy");
+        BOOST_CHECK(pred(bareObj));
+    }
+private:
+    StringVectorAsArgs mArgs;
+    Ice::CommunicatorPtr mCommunicator;
+    std::string mName;
+};
 
 }; /* End of namespace ProxyHelperTests */
 }; /* End of namespace AsteriskSCF */
 
-ASTERISK_SCF_ICEBOX_EXPORT IceBox::Service* create(Ice::CommunicatorPtr communicator)
+AsteriskSCF::ProxyHelperTests::ProxyHelperTestSuite::ProxyHelperTestSuite(const Ice::CommunicatorPtr& comm) :
+    mImpl(new AsteriskSCF::ProxyHelperTests::TestRunner(comm))
 {
-    return new AsteriskSCF::ProxyHelperTests::Test;
+    framework::master_test_suite().
+        add(BOOST_TEST_CASE(boost::bind(&TestRunner::run, mImpl)));
 }
+
+
+
diff --git a/test/ProxyHelper/ProxyHelperTests.cpp b/test/ProxyHelper/ProxyHelperTests.h
similarity index 55%
copy from test/ProxyHelper/ProxyHelperTests.cpp
copy to test/ProxyHelper/ProxyHelperTests.h
index 6b64e85..8095e5e 100644
--- a/test/ProxyHelper/ProxyHelperTests.cpp
+++ b/test/ProxyHelper/ProxyHelperTests.h
@@ -14,36 +14,28 @@
  * at the top of the source tree.
  */
 
-#include <AsteriskSCF/Helpers/PropertyHelper.h>
-#include <AsteriskSCF/Helpers/ProxyHelper.h>
-#include <AsteriskSCF/Testing/IceBoxBoostTest.h>
+#pragma once
+
+#include <Ice/Ice.h>
+#include <boost/shared_ptr.hpp>
 
 namespace AsteriskSCF
 {
 namespace ProxyHelperTests
 {
+class TestRunner;
 
-class Test : public IceBoxTest
+class ProxyHelperTestSuite
 {
 public:
-    Test()
-    {
-    }
-};
-
-//
-// Tests for the ProxyHelper facilities.
-//
-static bool init_unit_test()
-{
-    
-}
+    /**
+     * Registers the test suite with the global test suite. There isn't anything else that needs to be done.
+     **/
+    ProxyHelperTestSuite(const Ice::CommunicatorPtr& comm);
 
+private:
+    boost::shared_ptr<TestRunner> mImpl;
+};
 
-}; /* End of namespace ProxyHelperTests */
-}; /* End of namespace AsteriskSCF */
-
-ASTERISK_SCF_ICEBOX_EXPORT IceBox::Service* create(Ice::CommunicatorPtr communicator)
-{
-    return new AsteriskSCF::ProxyHelperTests::Test;
-}
+} /* End of namespace ProxyHelperTests */
+} /* End of namespace AsteriskSCF */
diff --git a/test/ProxyHelper/SimpleIf.ice b/test/ProxyHelper/SimpleIf.ice
new file mode 100644
index 0000000..828bbd9
--- /dev/null
+++ b/test/ProxyHelper/SimpleIf.ice
@@ -0,0 +1,27 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-2011, 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
+
+module AsteriskSCF
+{
+module ProxyHelperTests
+{
+interface SimpleTestIntf
+{
+    void hiThere();
+};
+}; /* End of module ProxyHelperTest */
+}; /* End of module AsteriskSCF */
\ No newline at end of file
diff --git a/test/UtilityTests.cpp b/test/UtilityTests.cpp
new file mode 100644
index 0000000..ee954c3
--- /dev/null
+++ b/test/UtilityTests.cpp
@@ -0,0 +1,134 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-2011, 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/Ice.h>
+#include <IceBox/IceBox.h>
+#include <IceUtil/Thread.h>
+
+#include <AsteriskSCF/Helpers/PropertyHelper.h>
+#include <AsteriskSCF/Helpers/ProxyHelper.h>
+
+#include "PropertyHelper/PropertyHelperTest.h"
+#include "ProxyHelper/ProxyHelperTests.h"
+#include "LocatorRegistration/LocatorRegistrationTest.h"
+
+#include <boost/test/unit_test.hpp>
+#include <boost/bind.hpp>
+#include <boost/test/debug.hpp>
+
+#include <vector>
+#include <string>
+
+using namespace std;
+using namespace boost::unit_test;
+
+//
+// Barebones test driver while I pull the rest of related code in and reorganize.
+//
+
+namespace AsteriskSCF
+{
+namespace UtilityTests
+{
+
+class TestRunner : public IceUtil::Thread
+{
+public:
+    TestRunner(const Ice::CommunicatorPtr& c, const Ice::StringSeq& args, const std::string& name):
+        mCommunicator(c),
+        mName(name)
+    {
+        std::vector<std::string> t(args);
+        t.insert(t.begin(), "ProxyHelperTests");
+        mArgs = StringVectorAsArgs(t);
+    }
+
+    void run()
+    {
+        int argc = mArgs.argc();
+        char** argv = mArgs.argv();
+
+        PropertyHelperTests::PropertyHelperTestSuite propertyTests(mCommunicator);
+        ProxyHelperTests::ProxyHelperTestSuite proxyHelperTests(mCommunicator);
+        LocatorRegistrationTests::LocatorRegistrationTestSuite locatorWrapperTest(mCommunicator);
+        
+        int result = ::boost::unit_test::unit_test_main(&init, argc, argv);
+
+        IceBox::ServiceManagerPrx mgr =
+            getProxy<IceBox::ServiceManagerPrx, Checked>(mCommunicator, "IceBoxManager.Proxy");
+        if (mgr)
+        {
+            try
+            {
+                mgr->stopService(mName);
+                mgr->shutdown();
+            }
+            catch (...)
+            {
+            }
+        }
+
+        if (mCommunicator->getProperties()->getPropertyWithDefault("AsteriskSCF.Test.Continue", "no") == "no")
+        {
+            try
+            {
+                mCommunicator->destroy();
+            }
+            catch (...)
+            {
+            }
+        }
+    }
+    
+    //
+    // Tests for the ProxyHelper facilities.
+    //
+    static bool init()
+    {
+        return true;
+    }
+    
+private:
+    StringVectorAsArgs mArgs;
+    Ice::CommunicatorPtr mCommunicator;
+    std::string mName;
+};
+
+class TestService : public IceBox::Service
+{
+public:
+
+    void start(const std::string& name, const Ice::CommunicatorPtr& comm, const Ice::StringSeq& args)
+    {
+        IceUtil::Handle<IceUtil::Thread> t = new TestRunner(comm, args, name);
+        t->start();
+    }
+
+    void stop()
+    {
+    }
+};
+
+}; /* End of namespace ProxyHelperTests */
+}; /* End of namespace AsteriskSCF */
+
+extern "C"
+{
+ASTERISK_SCF_ICEBOX_EXPORT IceBox::Service* create(Ice::CommunicatorPtr communicator)
+{
+    return new AsteriskSCF::UtilityTests::TestService;
+}
+}

commit 652741a0e5cc85baa21ec508b7fd3cf118446ec4
Author: Brent Eagles <beagles at digium.com>
Date:   Mon Apr 25 13:12:27 2011 -0230

    Initial commit of some in progress code.

diff --git a/include/AsteriskSCF/Helpers/PropertyHelper.h b/include/AsteriskSCF/Helpers/PropertyHelper.h
new file mode 100644
index 0000000..696bf75
--- /dev/null
+++ b/include/AsteriskSCF/Helpers/PropertyHelper.h
@@ -0,0 +1,173 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2011, 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 <Ice/Properties.h>
+#include <string>
+#include <vector>
+#include <boost/shared_ptr.hpp>
+
+namespace AsteriskSCF
+{
+
+/**
+ *
+ * A very simple helper function template that encapsulates a common pattern when doing property validation when
+ * initializing Ice clients and servers. It goes one step further that the xWithDefault variants of property "get"
+ * methods by setting the property if is not otherwise set. Why do this?  It can be handy if there is a convenient spot
+ * in your code to check a bunch of properties that you KNOW are going to be needed because of implementation details
+ * and you do not want to have to use the xWithDefault variants throughout your code. Note that this *DOES NOT* override
+ * any properties if they already exist.
+ *
+ **/
+inline void propGetSet(const Ice::PropertiesPtr& p, const std::string& propertyName, const std::string& value)
+{
+    p->setProperty(propertyName, p->getPropertyWithDefault(propertyName, value));
+}
+
+/**
+ *
+ * A generic helper template that can be specialized to help convert different types to std::strings
+ * for the StringVectorAsArgs template.
+ *
+ **/
+template <typename T>
+std::string convertToString(const T& t)
+{
+    return t;
+}
+
+/**
+ *
+ * StringVectorAsArgs is a class meant to be aggregated (but could also be derived from). It's intended use are for those
+ * situations where you are integrating code that requires the old C style an argument count and array of char* for
+ * passing arguments with code that has that data stored in string vector of some kind. NOTE: this is not thread
+ * safe! It would actually be pretty much impossible to truly make thread safe since argv() returns an array of char**
+ * that reference memory held by the instance.
+ *
+ **/
+class StringVectorAsArgs
+{
+public:
+
+    //
+    // Default and copy constructor.
+    //
+    StringVectorAsArgs()
+    {
+        std::vector<std::string> v;
+        mData.reset(new Data(v));
+    }
+
+    StringVectorAsArgs(const StringVectorAsArgs& props) 
+    {
+        mData.reset(new Data(props.args()));
+    }
+
+    template <typename V>
+    explicit StringVectorAsArgs(const V& rhs)
+    {
+        std::vector<std::string> v;
+        copyV(rhs, v);
+        mData.reset(new Data(v));
+    }
+
+    /**
+     * 
+     * Returns the argc equivalent of the vector.
+     *
+     * @returns the number or entries in argv.
+     *
+     **/
+    int argc()
+    {
+        return mData->mArgc;
+    }
+
+    /**
+     *
+     * Returns the argv equivalent of the vector (null terminated of course).
+     *
+     **/
+    char** argv()
+    {
+        return const_cast<char**>(static_cast<const char**>(&(mData->mArgv[0])));
+    }
+
+    /**
+     *
+     * Returns a copy of the original vector.
+     *
+     **/
+    std::vector<std::string> args() const
+    {
+        return mData->mArguments;
+    }
+
+    StringVectorAsArgs& operator=(const StringVectorAsArgs& rhs)
+    {
+        if (this == &rhs)
+        {
+            return *this;
+        }
+        mData.reset(new Data(rhs.args()));
+
+        return *this;
+    }
+
+private:
+
+    struct Data
+    {
+        std::vector<std::string> mArguments;
+        int mArgc;
+        std::vector<const char*> mArgv;
+
+        Data(const std::vector<std::string>& v) :
+            mArguments(v)
+        {
+            for (std::vector<std::string>::const_iterator i = mArguments.begin(); i != mArguments.end(); ++i)
+            {
+                mArgv.push_back(i->c_str());
+            }
+            mArgv.push_back(static_cast<const char*>(0));
+            mArgc = mArgv.size() -1;
+        }
+    };
+
+    //
+    // Specializations exist for the most commonly used values of T.  The general form allows for collections that a.)
+    // have a stl type iterator interface and b.) members can be directly assigned to std::string.
+    //
+    template <typename T>
+    void copyV(const T& src, std::vector<std::string>& dest)
+    {
+        for(T::const_iterator i = src.begin(); i != src.end(); ++i)
+        {
+            dest.push_back(convertToString(*i));
+        }
+    }
+        
+    boost::shared_ptr<Data> mData;
+};
+
+template<>
+void StringVectorAsArgs::copyV(const std::vector<std::string>& p, std::vector<std::string>& dest)
+{
+    dest = p;
+}
+
+};
diff --git a/include/AsteriskSCF/Helpers/ProxyHelper.h b/include/AsteriskSCF/Helpers/ProxyHelper.h
new file mode 100644
index 0000000..8d7153c
--- /dev/null
+++ b/include/AsteriskSCF/Helpers/ProxyHelper.h
@@ -0,0 +1,82 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2011, 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 <assert.h>
+#include <Ice/Communicator.h>
+
+namespace AsteriskSCF
+{
+/**
+ *
+ * Policy-enabled getProxy(): A "shorthand" mechanism for getting proxies from configuration files.  The getProxy()
+ * function encapsulates the code required to retrieve a proxy from Ice Properties in one step. The Policy classes allow
+ * the caller to control whether a checked or unchecked cast is performed to downcast the proxy object (remember: a
+ * checked cast results in a remote procedure call in this case, the unchecked cast does not).
+ *
+ **/
+
+/**
+ * Policy for performing checked casts.
+ */
+template <class T>
+CheckedCastPolicy
+{
+public:
+    T cast(const Ice::ObjectPrx& proxy)
+    {
+        return T::checkedCast(proxy);
+    }
+};
+
+/**
+ * Policy for performing unchecked casts.
+ */
+template <class T>
+UncheckedCastPolicy
+{
+public:
+    T cast(const Ice::ObjectPrx& proxy)
+    {
+        return T::uncheckedCast(proxy);
+    }
+};
+
+/**
+ *
+ * The getProxy call. NOTE: this function does not perform and release mode parameter checking (asserts for debug mode
+ * only), so the caller should do precondition validation if it at all possible for these arguments to be invalid.
+ * 
+ *
+ * @param comm An Ice communicator instance.
+ * @param property The name of the property that contains the stringified proxy.
+ * @param typedParam A proxy handle of the required type.
+ * @param policy A policy object instance.
+ *
+ * @returns An initialized proxy handle of the required type.
+ *
+ **/
+template <class T, class P = CheckedCastPolicy<T> >
+T getProxy(const Ice::CommunicatorPtr& comm, const std::string& property, T& typedParam = T(), const P& policy = P())
+{
+    assert(comm);
+    assert(!property.empty());
+    typedParam =  P.cast(comm->propertyToProxy(property));
+    return typedParam;
+}
+
+}; /* End of namespace AsteriskSCF */
diff --git a/include/AsteriskSCF/IceUtility.h b/include/AsteriskSCF/IceUtility.h
new file mode 100644
index 0000000..c9e5b7b
--- /dev/null
+++ b/include/AsteriskSCF/IceUtility.h
@@ -0,0 +1,22 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2011, 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 <AsteriskSCF/Helpers/ProxyHelper.h>
+#include <AsteriskSCF/Helpers/PropertyHelper.h>
+#include <AsteriskSCF/Listener/ListenerManager.h>
+
diff --git a/include/AsteriskSCF/Listener/ListenerManager.h b/include/AsteriskSCF/Listener/ListenerManager.h
new file mode 100644
index 0000000..a7f1f9d
--- /dev/null
+++ b/include/AsteriskSCF/Listener/ListenerManager.h
@@ -0,0 +1,295 @@
+/*
+ * Asterisk Scalable Communications Framework
+ *
+ * Copyright (C) 2010 -- Digium, Inc.
+ *
+ * All rights reserved.
+ */
+#pragma once
+
+#include <Ice/Ice.h>
+#include <IceStorm/IceStorm.h>
+#include <boost/thread/shared_mutex.hpp>
+#include <boost/thread/locks.hpp>
+#include <string>
+#include <algorithm>
+#include <vector>
+
+#include <IceUtil/Thread.h>
+
+namespace AsteriskSCF
+{
+/**
+ *
+ * Helper template for classes that need to implement listener style interfaces and use IceStorm
+ * to distribute updates.
+ *
+ **/
+template <class T>
+class ListenerManagerT : public IceUtil::Shared
+{
+    typedef std::vector<T> ListenerSeq;
+    typename std::vector<T>::iterator ListenerIter;
+
+    /**
+     *
+     * The InitializationThread allows the ListenerManager instance to initialize asynchronously,
+     * avoiding startup order issues. Note that notifications that are forwarded before
+     * initialization occurs are lost (subscriptions are not).
+     *
+     **/
+    class InitializationThread : public IceUtil::Thread
+    {
+    public:
+        InitializationThread(const typename IceUtil::Handle<ListenerManagerT>& mgr,
+                const IceUtil::Time& retryInterval) :
+            mMgr(mgr),
+            mStopped(false),
+            mRetryInterval(retryInterval)
+            
+        {
+        }
+
+        void run()
+        {
+            bool initialized = false;
+            IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+            while(!mStopped && !initialized)
+            {
+                mMonitor.timedWait(mRetryInterval);
+                initialized = mMgr->init();
+            }
+        }
+
+        void stop()
+        {
+            IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+            mStopped = true;
+            mMonitor.notify();
+        }
+
+    private:
+        IceUtil::Monitor<IceUtil::Mutex> mMonitor;
+        typename IceUtil::Handle<ListenerManagerT> mMgr;
+        bool mStopped;
+        const IceUtil::Time mRetryInterval;
+    };
+
+public:
+    ListenerManagerT(const IceStorm::TopicManagerPrx& topicManager, const std::string& topicName,
+            bool enableBackgroundInit,
+            const IceUtil::Time& retryInterval) :
+        mTopicManager(topicManager),
+        mTopicName(topicName),
+        mInitialized(false)
+    {
+        try
+        {
+            init();
+        }
+        catch(const Ice::Exception&)
+        {
+        }
+        
+        if(!mInitialized && enableBackgroundInit)
+        {
+            mInitThread = new InitializationThread(this, retryInterval);
+            mInitThread->start();
+        }
+    }
+
+    virtual ~ListenerManagerT()
+    {
+        if(mTopic)
+        {
+            try
+            {
+                mTopic->destroy();
+            }
+            catch(...)
+            {
+                //
+                // Destructors are no-throw!
+                //
+            }
+        }
+    }
+
+    //
+    // NOTE: The current implementation is a little fast and loose here. Inconsistent conditions
+    // and whatnot are not flagged.
+    //
+    bool addListener(const T& listener)
+    {
+        bool tryInit = false;
+        bool added = false;
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            if(std::find(mListeners.begin(), mListeners.end(), listener) == mListeners.end())
+            {
+                mListeners.push_back(listener);
+                added = true;
+            }
+            tryInit = !mInitialized && !mInitThread;
+        }
+
+        if (!tryInit)
+        {
+            if (added)
+            {
+                IceStorm::QoS qos;
+                qos["reliability"] = "ordered";
+
+                try
+                {
+                    mTopic->subscribeAndGetPublisher(qos, listener);
+                }
+                catch (const IceStorm::AlreadySubscribed&)
+                {
+                    //
+                    // This indicates some kind of inconsistent state or could
+                    // happen if this is a replica.
+                    //
+                }
+            }
+        }
+        else
+        {
+            init();
+        }
+        
+        return added;
+    }
+
+    bool removeListener(const T& listener)
+    {
+        T& proxyToUnsubscribe;
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            typename std::vector<T>::iterator i = std::find(mListeners.begin(), mListeners.end(), listener);
+            if(i != mListeners.end())
+            {
+                mListeners.erase(i);
+                if(mInitialized)
+                {
+                    proxyToUnsubscribe = listener;
+                }
+            }
+        }
+        if (proxyToUnsubscibe)
+        {
+            mTopic->unsubscribe(proxyToUnsubscribe);
+            return true;
+        }
+        return false;
+    }
+
+    std::vector<T> getListeners()
+    {
+        boost::shared_lock<boost::shared_mutex> lock(mLock);
+        return mListeners;
+    }
+
+    bool isSuspended()
+    {
+        boost::shared_lock<boost::shared_mutex> lock(mLock);
+        return !mInitialized;
+    }
+
+    void stop()
+    {
+        if(mInitThread)
+        {
+            mInitThread->stop();
+        }
+    }
+
+protected:
+    boost::shared_mutex mLock;
+    std::string mTopicName;
+    IceStorm::TopicPrx mTopic;
+    IceStorm::TopicManagerPrx mTopicManager;
+    T mPublisher;
+    ListenerSeq mListeners;
+    IceUtil::Handle<InitializationThread> mInitThread;
+
+    bool mInitialized;
+
+    bool init()
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        if (mInitialized)
+        {
+            return mInitialized;
+        }
+
+        //
+        // This *might* be the first time we attempt to access IceStorm. If so, then the connection
+        // might fail because it may not be available at the moment. If so, we "eat" the resulting
+        // SocketException and reply that we are not initialized. All other exceptions propogate
+        // out as they typically indicated a terminal condition. 
+        //
+        try
+        {
+            mTopic = mTopicManager->retrieve(mTopicName);
+        }
+        catch (const IceStorm::NoSuchTopic&)
+        {
+            //
+            // We ignore this.. we'll try to create it below if it doesn't exist.
+            //
+        }
+        catch (const Ice::SocketException&)
+        {
+            return false;
+        }
+
+        if(!mTopic)
+        {
+            try
+            {
+                mTopic = mTopicManager->create(mTopicName);
+            }
+            catch(const IceStorm::TopicExists&)
+            {
+                //
+                // In case there is a race condition when creating the topic.
+                //
+                mTopic = mTopicManager->retrieve(mTopicName);
+            }
+        }
+
+        if(!mTopic)
+        {
+            return mInitialized;
+        }
+        mPublisher = T::uncheckedCast(mTopic->getPublisher());
+
+        if(mListeners.size() > 0)
+        {
+            for(typename std::vector<T>::iterator i = mListeners.begin(); i != mListeners.end(); ++i)
+            {
+                //
+                // This could be made configurable, but for the ordered QoS is appropriate for most
+                // listener models.
+                //
+                IceStorm::QoS qos;
+                qos["reliability"] = "ordered";
+
+                try
+                {
+                    mTopic->subscribeAndGetPublisher(qos, *i);
+                }
+                catch(const IceStorm::AlreadySubscribed&)
+                {
+                    //
+                    // This indicates some kind of inconsistent state.
+                    //
+                }
+            }
+        }
+        mInitialized = true;
+        return mInitialized;
+    }
+};
+} /* End of namespace AsteriskSCF */
diff --git a/test/ListenerManager/ListenerManagerTests.cpp b/test/ListenerManager/ListenerManagerTests.cpp
new file mode 100644
index 0000000..a413887
--- /dev/null
+++ b/test/ListenerManager/ListenerManagerTests.cpp
@@ -0,0 +1,27 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-2011, 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/bind.hpp>
+#include <boost/test/unit_test.hpp>
+#include <boost/test/debug.hpp>
+
+#include <Ice/Ice.h>
+#include <IceBox/IceBox.h>
+
+#include <AsteriskSCF/IceUtility.h>
+
+
+
diff --git a/test/PropertyHelper/PropertyHelperTest.cpp b/test/PropertyHelper/PropertyHelperTest.cpp
new file mode 100644
index 0000000..b2bc8d8
--- /dev/null
+++ b/test/PropertyHelper/PropertyHelperTest.cpp
@@ -0,0 +1,83 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-2011, 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_DYN_LINK
+
+#include <AsteriskSCF/Helpers/PropertyHelper.h>
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <vector>
+
+extern "C"
+{
+    void runPropertyHelperTest();
+}
+
+namespace AsteriskSCF
+{
+
+template <>
+std::string convertToString(const int& t)
+{
+    return boost::lexical_cast<std::string>(t);
+}
+
+};
+
+using namespace AsteriskSCF;
+
+void testContents(StringVectorAsArgs& t)
+{
+    BOOST_REQUIRE(t.argc() == 3);
+    BOOST_CHECK(strcmp(t.argv()[0], "1") == 0);
+    BOOST_CHECK(strcmp(t.argv()[1], "3") == 0);
+    BOOST_CHECK(strcmp(t.argv()[2], "2") == 0);
+    std::vector<std::string> v(t.args());
+    BOOST_REQUIRE(v.size() == 3);
+    BOOST_CHECK(v[0] == "1");
+    BOOST_CHECK(v[1] == "3");
+    BOOST_CHECK(v[2] == "2");
+}
+
+void runPropertyHelperTest()
+{
+    //
+    // Simple check of the specialization.
+    //
+    BOOST_CHECK(convertToString(1) == "1");
+    BOOST_CHECK(convertToString("1") == "1");
+
+    //
+    // Now let's see if it works with the StringVectorAsArgs class
+    //
+    std::vector<int> intVector;
+    intVector.push_back(1);
+    intVector.push_back(3);
+    intVector.push_back(2);
+
+    StringVectorAsArgs converted(intVector);
+    testContents(converted);
+    StringVectorAsArgs copyOfConverted(converted);
+    testContents(copyOfConverted);
+
+    StringVectorAsArgs defaultConstructor;
+    defaultConstructor = copyOfConverted;
+    testContents(defaultConstructor);
+
+    defaultConstructor = defaultConstructor;
+    testContents(defaultConstructor);
+}
+
diff --git a/test/PropertyHelper/main.cpp b/test/PropertyHelper/main.cpp
new file mode 100644
index 0000000..ecc1c36
--- /dev/null
+++ b/test/PropertyHelper/main.cpp
@@ -0,0 +1,13 @@
+#include <iostream>
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MODULE PropertyTestDriver
+#include <boost/test/unit_test.hpp>
+
+using namespace std;
+
+extern "C" void runPropertyHelperTest();
+
+BOOST_AUTO_TEST_CASE( runTest )
+{
+    runPropertyHelperTest();
+}
diff --git a/test/ProxyHelper/ProxyHelperTests.cpp b/test/ProxyHelper/ProxyHelperTests.cpp
new file mode 100644
index 0000000..6b64e85
--- /dev/null
+++ b/test/ProxyHelper/ProxyHelperTests.cpp
@@ -0,0 +1,49 @@
+/*
+ * Asterisk SCF -- An open-source communications framework.
+ *
+ * Copyright (C) 2010-2011, 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 <AsteriskSCF/Helpers/PropertyHelper.h>
+#include <AsteriskSCF/Helpers/ProxyHelper.h>
+#include <AsteriskSCF/Testing/IceBoxBoostTest.h>
+
+namespace AsteriskSCF
+{
+namespace ProxyHelperTests
+{
+
+class Test : public IceBoxTest
+{
+public:
+    Test()
+    {
+    }
+};
+
+//
+// Tests for the ProxyHelper facilities.
+//
+static bool init_unit_test()
+{
+    
+}
+
+
+}; /* End of namespace ProxyHelperTests */
+}; /* End of namespace AsteriskSCF */
+
+ASTERISK_SCF_ICEBOX_EXPORT IceBox::Service* create(Ice::CommunicatorPtr communicator)
+{
+    return new AsteriskSCF::ProxyHelperTests::Test;
+}

commit fd811e3d47f7b1ac5fb9532490a7c094ce22bf74
Author: Kevin P. Fleming <kpfleming at digium.com>
Date:   Wed Apr 27 09:03:11 2011 -0500

    Remove obsolete setting of 'bindir'.

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2beaa3d..d49205b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -2,7 +2,6 @@ asterisk_scf_project(ice-util-cpp 3.4)
 
 if (integrated_build STREQUAL "true")
 	set(utils_dir ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
-	set(utils_bindir ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
 endif()
 
 add_subdirectory(SmartProxy)

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


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



More information about the asterisk-scf-commits mailing list