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

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Fri Mar 30 12:51:51 CDT 2012


branch "retry_deux" has been updated
       via  6227c52f466b42b7de46d7bbaaf8b3d651f16458 (commit)
      from  080fec7062496aa20104d2218773b63af11bd65f (commit)

Summary of changes:
 include/AsteriskSCF/Operations/ExceptionWrapper.h  |  110 +++++
 include/AsteriskSCF/Operations/OperationMonitor.h  |  482 ++++++++++++++++++++
 src/Operations/CMakeLists.txt                      |    1 +
 src/Operations/OperationMonitor.cpp                |   86 ++++
 test/CMakeLists.txt                                |    2 +
 test/OperationMonitor/OperationMonitorTest.cpp     |  162 +++++++
 .../OperationMonitorTest.h}                        |    8 +-
 test/UtilityTests.cpp                              |    2 +
 8 files changed, 849 insertions(+), 4 deletions(-)
 create mode 100755 include/AsteriskSCF/Operations/ExceptionWrapper.h
 create mode 100755 include/AsteriskSCF/Operations/OperationMonitor.h
 create mode 100755 src/Operations/OperationMonitor.cpp
 create mode 100644 test/OperationMonitor/OperationMonitorTest.cpp
 copy test/{OperationContextCache/OperationContextCacheTest.h => OperationMonitor/OperationMonitorTest.h} (83%)


- Log -----------------------------------------------------------------
commit 6227c52f466b42b7de46d7bbaaf8b3d651f16458
Author: Brent Eagles <beagles at digium.com>
Date:   Fri Mar 30 15:21:08 2012 -0230

    Move operation monitor from current bridge component work into ASCFIceUtilCpp.

diff --git a/include/AsteriskSCF/Operations/ExceptionWrapper.h b/include/AsteriskSCF/Operations/ExceptionWrapper.h
new file mode 100755
index 0000000..84933b0
--- /dev/null
+++ b/include/AsteriskSCF/Operations/ExceptionWrapper.h
@@ -0,0 +1,110 @@
+/*
+ * 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/Exception.h>
+#include <Ice/LocalException.h>
+#include <exception>
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include <AsteriskSCF/Operations/OperationContextCache.h>
+
+namespace AsteriskSCF
+{
+
+namespace Operations
+{
+
+typedef boost::shared_ptr<IceUtil::Exception> ExceptionPtr;
+class ExceptionWrapper;
+typedef boost::shared_ptr<ExceptionWrapper> ExceptionWrapperPtr;
+
+/** 
+ * ExceptionWrapper is OperationContextCookie derived class for
+ * storing exceptional results for use later on. 
+ */
+class ExceptionWrapper
+{
+
+public:
+    /**
+     * Several conversion constructors are provided for
+     * convenience. While conversion constructors can be problematic,
+     * the nature of this class is "to wrap"... so there!
+     */
+    explicit
+    ExceptionWrapper(const IceUtil::Exception& ex) :
+        mException(ex.ice_clone())
+    {
+    }
+
+    /**
+     * Unfortunately std::exception does not provide a way to clone
+     * the most-derived type at runtime. As the ultimate goal is to
+     * send this exception to an Ice client, we need only do as well
+     * as the Ice runtime can -- create an
+     * Ice::UnknownException(). The __FILE__ and __LINE__ will not be
+     * related to the original exception, but does have value in that
+     * it shows where the std::exception->Ice exception translation
+     * occurs.
+     */
+    explicit
+    ExceptionWrapper(const std::exception& ex) :
+        mException(new Ice::UnknownException(__FILE__, __LINE__, ex.what()))
+    {
+    }
+
+    /**
+     * Intended for those catch (...) cases. Something can be passed back,
+     * but like std::exceptions, Ice will end up sending an
+     * UnknownException.
+     */
+    explicit
+    ExceptionWrapper(const std::string& msg) :
+       mException(new Ice::UnknownException(__FILE__, __LINE__, msg))
+    {
+    }
+
+    /**
+     * Accessor to get the wrapped exception.
+     */
+    ExceptionPtr exception() const
+    {
+        return mException;
+    }
+
+    static ExceptionWrapperPtr create(const Ice::Exception& x)
+    {
+        return ExceptionWrapperPtr(new ExceptionWrapper(x));
+    }
+
+    static ExceptionWrapperPtr create(const std::exception& x)
+    {
+        return ExceptionWrapperPtr(new ExceptionWrapper(x));
+    }
+
+    static ExceptionWrapperPtr create(const std::string& msg)
+    {
+        return ExceptionWrapperPtr(new ExceptionWrapper(msg));
+    }
+
+private:
+    ExceptionPtr mException;
+};
+
+} /* end of namespace Operations */
+} /* end of namespace AsteriskSCF */
diff --git a/include/AsteriskSCF/Operations/OperationMonitor.h b/include/AsteriskSCF/Operations/OperationMonitor.h
new file mode 100755
index 0000000..6be007c
--- /dev/null
+++ b/include/AsteriskSCF/Operations/OperationMonitor.h
@@ -0,0 +1,482 @@
+/*
+ * 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/Exception.h>
+#include <exception>
+#include <string>
+#include <boost/shared_ptr.hpp>
+#include <boost/enable_shared_from_this.hpp>
+#include <AsteriskSCF/Operations/OperationContext.h>
+#include <AsteriskSCF/Operations/OperationContextCache.h>
+#include <AsteriskSCF/Operations/ExceptionWrapper.h>
+
+namespace AsteriskSCF
+{
+namespace Operations
+{
+
+/**
+ * The ContextMonitor provides a mechanism for waiting for a result when multiple 
+ * upcalls occur for the same OperationContext. Of course this is only relevant for 
+ * non-AMD implementations.
+ */
+class ContextMonitor : public IceUtil::Shared
+{
+public:
+    ContextMonitor() :
+        mCompleted(false),
+        mCancelled(false)
+    {
+    }
+
+    bool isCompleted() 
+    {
+        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+        return mCompleted;
+    }
+
+    bool waitForResults()
+    {
+        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+        while (!mCompleted && !mCancelled)
+        {
+            mMonitor.wait();
+        }
+        return mCompleted;
+    }
+
+    void setCompleted()
+    {
+        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+        mCompleted = true;
+        mMonitor.notify();
+    }
+
+    /**
+     * Revisit: this was added before there was a specific use for it. If it is not referenced, 
+     * it probably should be removed (along with the related member variable of course).
+     */
+    void cancel()
+    {
+        IceUtil::Monitor<IceUtil::Mutex>::Lock lock(mMonitor);
+        mCancelled = true;
+        mMonitor.notify();
+    }
+
+private:
+    bool mCompleted;
+    bool mCancelled;
+    IceUtil::Monitor<IceUtil::Mutex> mMonitor;
+};
+typedef IceUtil::Handle<ContextMonitor> ContextMonitorPtr;
+
+class ContextData : virtual public AsteriskSCF::Operations::OperationContextCookie,
+                    virtual public boost::enable_shared_from_this<ContextData>
+{
+public:
+    ContextData() :
+        mMonitor(new ContextMonitor)
+    {
+    }
+
+    /**
+     * Get a results monitor object for this context's data.
+     */
+    ContextMonitorPtr getMonitor();
+
+    /**
+     * If the operations performed for this operation context result
+     * in an exception that should be reported back to the client,
+     * then this should be non-null and contain a wrapper to the
+     * exception to be passed back.
+     */
+    ExceptionWrapperPtr getException();
+
+    void setException(const ExceptionWrapperPtr& exception);
+
+    /**
+     * A quick, single point accessor to determine the completion
+     * statius of the related operation. The alternative would be to
+     * get the monitor and ask it.
+     */
+    bool isCompleted();
+
+    virtual void setCompleted()
+    {
+        mMonitor->setCompleted();
+        onSetCompleted();
+    }
+   
+protected:
+    IceUtil::Mutex mLock;
+    
+    ContextMonitorPtr mMonitor;
+    ExceptionWrapperPtr mExceptionResult;
+
+    virtual void onSetException()
+    {
+    }
+
+    virtual void onSetCompleted()
+    {
+    }
+};
+typedef boost::shared_ptr<ContextData> ContextDataPtr;
+
+/**
+ * Template derived class of ContextData.  
+ * TODO: comment on rationale. The general idea is that the casting
+ * can occur on the context result data, not on what is inside it. 
+ * Derived classes are also a bit more interesting because they will 
+ * be specific to a certain result type.. but this whole notion needs
+ * to be worded better. Hence the TODO.
+ */
+
+template <typename RT>
+class ContextResultData : virtual public ContextData
+{
+public:
+    void setResult(const RT& val);
+
+    RT getResult()
+    {
+        return mResult;
+    }
+
+protected:
+    virtual void onSetResult() {}
+    RT mResult;
+};
+
+template <typename RT>
+void ContextResultData<RT>::setResult(const RT& val)
+{
+    if (isCompleted())
+    {
+        return;
+    }
+    
+    IceUtil::LockT<IceUtil::Mutex> lock(mLock);
+    mResult = val;
+    setCompleted();
+    onSetResult();
+}
+
+/**
+ * Not every AMD type operation has a result value.
+ */
+template <class CB>
+class AMDContextData : virtual public ContextData
+{
+public:
+    template<class T >
+    class AMDProxy : virtual public T::element_type, virtual public IceUtil::Shared
+    {
+    public:
+        void ice_response()
+        {
+            if (mParent)
+            {
+                mParent->setCompleted();
+                //
+                // The reset breaks the mutual reference count.
+                //
+                mParent.reset();
+            }
+        }
+
+        void ice_exception(const std::exception& ex)
+        {
+            if (mParent)
+            {
+                const Ice::Exception* ix = dynamic_cast<const Ice::Exception*>(&ex);
+                if (ix)
+                {
+                    mParent->setException(ExceptionWrapper::create(*ix));
+                    return;
+                }
+                mParent->setException(ExceptionWrapper::create(ex));
+                //
+                // The reset breaks the mutual reference count.
+                //
+                mParent.reset();
+            }
+        }
+    
+        void ice_exception()
+        {
+            if (mParent)
+            {
+                mParent->setException(ExceptionWrapper::create("Unexpected unknown exception"));
+                //
+                // The reset breaks the mutual reference count.
+                //
+                mParent.reset();
+            }
+        }
+
+        AMDProxy(const boost::shared_ptr<ContextData>& d) :
+            mParent(d)
+        {
+        }
+
+    private:
+        boost::shared_ptr<ContextData> mParent;
+    };
+
+    AMDContextData() {}
+    AMDContextData(const CB& cb)
+    {
+        mCallbacks.push_back(cb);
+    }
+
+    void addCB(const CB& cbPtr);
+
+    CB getProxy()
+    {
+        {
+            // 
+            // We need to do this lazy initialization because we need to setup the relationship
+            // between the AMD proxy and this object instance *after* this object instance
+            // has been fully constructed. Otherwise we can get into some nasty stuff.
+            //
+            IceUtil::LockT<IceUtil::Mutex> lock(mLock);
+            if (!mAMDProxy)
+            {
+                mAMDProxy = new AMDProxy<CB>(shared_from_this());
+            }
+        }
+        return mAMDProxy;
+    }
+
+private:
+    void onSetException();
+    void onSetCompleted();
+    CB mAMDProxy;
+    std::vector<CB> mCallbacks;
+};
+
+template <class CB>
+void AMDContextData<CB>::addCB(const CB& cbPtr)
+{
+    IceUtil::LockT<IceUtil::Mutex> lock(mLock);
+    if (isCompleted())
+    {
+        if (mExceptionResult)
+        {
+            cbPtr->ice_exception(*(mExceptionResult->exception()));
+        }
+        else
+        {
+            cbPtr->ice_response();
+        }
+        return;
+    }
+    mCallbacks.push_back(cbPtr);
+}
+
+template <class CB>
+void AMDContextData<CB>::onSetException()
+{
+    for (typename std::vector<CB>::const_iterator iter= mCallbacks.begin();
+         iter != mCallbacks.end(); ++iter)
+    {
+        (*iter)->ice_exception(*(mExceptionResult->exception()));
+    }
+}
+
+template <class CB>
+void AMDContextData<CB>::onSetCompleted()
+{
+    for (typename std::vector<CB>::const_iterator iter= mCallbacks.begin();
+         iter != mCallbacks.end(); ++iter)
+    {
+        (*iter)->ice_response();
+    }
+}
+
+/**
+ *
+ * AMDContextResultData has the added feature that it can be passed as
+ * an AMD callback object for CB's element type. The standard AMD
+ * callback methods are overridden and behave in the same manner as
+ * the synchronous result's setResult/setException methods. The AMD
+ * ContextResultData also stores all AMD callback objects that are
+ * part of asynchronous upcalls for the same operation context.
+ *
+ **/
+template <typename RT, class CB>
+class AMDContextResultData : virtual public ContextResultData<RT>, virtual public ContextData
+{
+public:
+    template< typename RTi, class CBi >
+    class AMDProxy : virtual public CBi::element_type, virtual public IceUtil::Shared
+    {
+    public:
+        void ice_response(const RTi& result)
+        {
+            if (mParent)
+            {
+                mParent->setResult(result);
+                //
+                // The reset breaks the mutual reference count.
+                //
+                mParent.reset();
+            }
+        }
+
+        void ice_exception(const std::exception& ex)
+        {
+            if (mParent)
+            {
+                const Ice::Exception* ix = dynamic_cast<const Ice::Exception*>(&ex);
+                if (ix)
+                {
+                    mParent->setException(ExceptionWrapper::create(*ix));
+                    return;
+                }
+                mParent->setException(ExceptionWrapper::create(ex));
+                //
+                // The reset breaks the mutual reference count.
+                //
+                mParent.reset();
+            }
+        }
+    
+        void ice_exception()
+        {
+            if (mParent)
+            {
+                mParent->setException(ExceptionWrapper::create("Unexpected unknown exception"));
+                //
+                // The reset breaks the mutual reference count.
+                //
+                mParent.reset();
+            }
+        }
+
+        AMDProxy(const boost::shared_ptr<AMDContextResultData<RTi, CBi> >& d) :
+            mParent(d)
+        {
+        }
+
+    private:
+        boost::shared_ptr<AMDContextResultData<RTi, CBi> > mParent;
+    };
+
+    AMDContextResultData()
+    {
+    }
+
+    AMDContextResultData(const CB& cb)
+    {
+        mCallbacks.push_back(cb);
+    }
+
+    CB getProxy()
+    {
+        {
+            // 
+            // We need to do this lazy initialization because we need to setup the relationship
+            // between the AMD proxy and this object instance *after* this object instance
+            // has been fully constructed. Otherwise we can get into some nasty stuff.
+            //
+            IceUtil::Mutex::Lock lock(mLock);
+            if (!mAMDProxy)
+            {
+                mAMDProxy = new AMDProxy<RT, CB>(
+                    boost::dynamic_pointer_cast<AMDContextResultData<RT, CB> >(shared_from_this()));
+            }
+        }
+        return mAMDProxy;
+    }
+    
+    void addCB(const CB& cbPtr)
+    {
+        IceUtil::LockT<IceUtil::Mutex> lock(mLock);
+        if (ContextData::isCompleted())
+        {
+            if (mExceptionResult)
+            {
+                cbPtr->ice_exception(*(mExceptionResult->exception()));
+            }
+            else
+            {
+                cbPtr->ice_response(ContextResultData<RT>::getResult());
+            }
+            return;
+        }
+        mCallbacks.push_back(cbPtr);
+    }
+    
+private:
+    void onSetResult()
+    {
+        for (typename std::vector<CB>::const_iterator iter = mCallbacks.begin();
+             iter != mCallbacks.end(); ++iter)
+        {
+            (*iter)->ice_response(ContextResultData<RT>::getResult());
+        }
+    }
+
+    void onSetException()
+    {
+        for (typename std::vector<CB>::const_iterator iter= mCallbacks.begin();
+             iter != mCallbacks.end(); ++iter)
+        {
+            (*iter)->ice_exception(*(mExceptionResult->exception()));
+        }
+    }
+    CB mAMDProxy;
+    std::vector<CB> mCallbacks;
+};
+
+/** 
+ * Simple file scope helper for the "add" methods. The signatures for
+ * these methods do not include any kind of results, so we only need
+ * to consider exceptions and one method will do for all of that. This
+ * function returns true if the caller should proceed with the actual
+ * operations or false if it can assume that it has already been done
+ * and the results have been obtained (and thrown if necessary in this
+ * case)
+ */
+ContextDataPtr checkAndThrow(const AsteriskSCF::Operations::OperationContextCachePtr& cache,
+    const AsteriskSCF::System::V1::OperationContextPtr& context);
+
+
+template <class DT, class AT>
+DT getContext(const AsteriskSCF::Operations::OperationContextCachePtr& cache,
+    const AsteriskSCF::System::V1::OperationContextPtr& context,
+    const AT& amdCallback)
+{
+    DT c(new typename DT::element_type);
+    AsteriskSCF::Operations::OperationContextCookiePtr o;
+     
+    if (!cache->addOperationContext(context, c, o))
+    {
+        c = boost::dynamic_pointer_cast<typename DT::element_type>(o);
+        assert(c);
+        c->addCB(amdCallback);
+        return DT();
+    }
+    c->addCB(amdCallback);
+    return c;
+}
+
+} /* End of namespace Operations */
+} /* End of namespace AsteriskSCF */
diff --git a/src/Operations/CMakeLists.txt b/src/Operations/CMakeLists.txt
index fb30822..900941f 100644
--- a/src/Operations/CMakeLists.txt
+++ b/src/Operations/CMakeLists.txt
@@ -1,2 +1,3 @@
 astscf_component_add_files(ASTSCFIceUtilCpp OperationContextCache.cpp)
 astscf_component_add_files(ASTSCFIceUtilCpp OperationContext.cpp)
+astscf_component_add_files(ASTSCFIceUtilCpp OperationMonitor.cpp)
diff --git a/src/Operations/OperationMonitor.cpp b/src/Operations/OperationMonitor.cpp
new file mode 100755
index 0000000..3e7dec3
--- /dev/null
+++ b/src/Operations/OperationMonitor.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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/Operations/OperationMonitor.h>
+
+namespace AsteriskSCF
+{
+namespace Operations
+{
+
+ContextMonitorPtr ContextData::getMonitor()
+{
+    return mMonitor;
+}
+
+ExceptionWrapperPtr ContextData::getException()
+{
+    IceUtil::LockT<IceUtil::Mutex> lock(mLock);
+    return mExceptionResult;
+}
+
+void ContextData::setException(const ExceptionWrapperPtr& exception)
+{
+    IceUtil::LockT<IceUtil::Mutex> lock(mLock);
+    mExceptionResult = exception;
+    onSetException();
+    mMonitor->setCompleted();
+}
+
+bool ContextData::isCompleted()
+{
+    return mMonitor->isCompleted();
+}
+
+ContextDataPtr checkAndThrow(const AsteriskSCF::Operations::OperationContextCachePtr& cache,
+    const AsteriskSCF::System::V1::OperationContextPtr& context)
+{
+    ContextDataPtr contextData(new ContextData);
+    AsteriskSCF::Operations::OperationContextCookiePtr oldContextData;
+    if (!cache->addOperationContext(context, contextData, oldContextData))
+    {
+        assert(oldContextData);
+        contextData = boost::dynamic_pointer_cast<ContextData>(oldContextData);
+        assert(contextData);
+        if (!contextData)
+        {
+            return ContextDataPtr();
+        }
+
+        //
+        // TODO: A safer way to do this would be to surround this with
+        // a while() loop that checks for completion status. I'm a
+        // little hesitant to do this since there are no mechanisms
+        // for clean shutdown right now.
+        //
+        contextData->getMonitor()->waitForResults();
+
+        //
+        // We can at least do this for debug builds.
+        //
+        assert(contextData->getMonitor()->isCompleted());
+        ExceptionWrapperPtr exception = contextData->getException();
+        if (exception)
+        {
+            exception->exception()->ice_throw();
+        }
+        return ContextDataPtr();
+    }
+    return contextData;
+}
+
+} /* End of namespace Operations */
+} /* End of namespace AsteriskSCF */
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6c3e4fe..05a749c 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -9,6 +9,8 @@ astscf_component_add_files(ASTSCFIceUtilCppTest ProxyHelper/ProxyHelperTests.cpp
 astscf_component_add_files(ASTSCFIceUtilCppTest ProxyHelper/ProxyHelperTests.h)
 astscf_component_add_files(ASTSCFIceUtilCppTest OperationContextCache/OperationContextCacheTest.cpp)
 astscf_component_add_files(ASTSCFIceUtilCppTest OperationContextCache/OperationContextCacheTest.h)
+astscf_component_add_files(ASTSCFIceUtilCppTest OperationMonitor/OperationMonitorTest.cpp)
+astscf_component_add_files(ASTSCFIceUtilCppTest OperationMonitor/OperationMonitorTest.h)
 astscf_component_add_files(ASTSCFIceUtilCppTest UtilityTests.cpp)
 astscf_component_add_ice_libraries(ASTSCFIceUtilCppTest IceBox)
 astscf_component_add_boost_libraries(ASTSCFIceUtilCppTest unit_test_framework date_time thread)
diff --git a/test/OperationMonitor/OperationMonitorTest.cpp b/test/OperationMonitor/OperationMonitorTest.cpp
new file mode 100644
index 0000000..d4cb7df
--- /dev/null
+++ b/test/OperationMonitor/OperationMonitorTest.cpp
@@ -0,0 +1,162 @@
+/*
+ * 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/Properties.h>
+#include <Ice/Initialize.h>
+#include <IceUtil/Thread.h>
+
+#include <AsteriskSCF/Operations/OperationContextCache.h>
+#include <AsteriskSCF/Operations/OperationMonitor.h>
+#include <AsteriskSCF/Logger.h>
+
+#include <boost/lexical_cast.hpp>
+#include <boost/test/unit_test.hpp>
+#include <string>
+#include <vector>
+
+#include "OperationMonitorTest.h"
+
+using namespace AsteriskSCF;
+using namespace AsteriskSCF::System::V1;
+using namespace AsteriskSCF::Operations;
+using namespace AsteriskSCF::System::Logging;
+using namespace std;
+
+namespace
+{
+
+class NotifierThread : public IceUtil::Thread
+{
+public:
+    NotifierThread(const ContextDataPtr& data) :
+        mData(data)
+    {
+    }
+
+    void run()
+    {
+        //
+        // Just sleep a couple of seconds.
+        //
+        IceUtil::ThreadControl::sleep(IceUtil::Time::seconds(2));            
+        mData->setCompleted();
+    }
+
+private:
+    ContextDataPtr mData;
+};
+
+void testOpMonitorCompleted()
+{
+    ContextDataPtr d(new ContextData);
+    IceUtil::Handle<NotifierThread> notifierThread(new NotifierThread(d));
+
+    notifierThread->run();
+    BOOST_CHECK(d->getMonitor()->waitForResults());
+    BOOST_CHECK(d->isCompleted());
+}
+
+class ExceptionThread : public IceUtil::Thread
+{
+public:
+    ExceptionThread(const ContextDataPtr& data) :
+        mData(data)
+    {
+    }
+
+    void run()
+    {
+        try
+        {
+            IceUtil::ThreadControl::sleep(IceUtil::Time::seconds(2));
+            throw Ice::ObjectNotExistException(__FILE__, __LINE__);
+        }
+        catch (const Ice::Exception& ex)
+        {
+            mData->setException(ExceptionWrapper::create(ex));
+        }
+    }
+
+private:
+    ContextDataPtr mData;
+};
+
+void testOpMonitorExceptionCompleted()
+{
+    ContextDataPtr d(new ContextData);
+    IceUtil::Handle<ExceptionThread> t(new ExceptionThread(d));
+    t->run();
+    BOOST_CHECK(d->getMonitor()->waitForResults());
+    BOOST_CHECK(d->isCompleted());
+
+    ExceptionWrapperPtr e = d->getException();
+    BOOST_REQUIRE(e);
+    Ice::ObjectNotExistException te(__FILE__, __LINE__);
+    BOOST_CHECK(e->exception()->ice_name() == te.ice_name());
+}
+
+typedef ContextResultData<string> StringContextData;
+typedef boost::shared_ptr<StringContextData> StringContextDataPtr;
+
+template <typename T>
+class SetValueThread : public IceUtil::Thread
+{
+public:
+    SetValueThread(const StringContextDataPtr& data, const T& v) :
+        mData(data),
+        mValue(v)
+    {
+    }
+
+    void run()
+    {
+        //
+        // Just sleep a couple of seconds.
+        //
+        IceUtil::ThreadControl::sleep(IceUtil::Time::seconds(2));            
+        mData->setResult(mValue);
+    }
+
+private:
+    StringContextDataPtr mData;
+    T mValue;
+};
+
+void testOpMonitorValueCompleted()
+{
+    StringContextDataPtr d(new StringContextData);
+    IceUtil::Handle<SetValueThread<string> > t(new SetValueThread<string>(d, "hey there"));
+
+    t->run();
+    BOOST_CHECK(d->getMonitor()->waitForResults());
+    BOOST_CHECK(d->isCompleted());
+    string r = d->getResult();
+    BOOST_CHECK(r == "hey there");
+}
+
+} // anonymous namespace
+
+using namespace boost::unit_test;
+
+AsteriskSCF::OperationMonitorTests::OperationMonitorTestSuite::OperationMonitorTestSuite()
+{
+    framework::master_test_suite().
+        add(BOOST_TEST_CASE(testOpMonitorCompleted));
+    framework::master_test_suite().
+        add(BOOST_TEST_CASE(testOpMonitorExceptionCompleted));
+    framework::master_test_suite().
+        add(BOOST_TEST_CASE(testOpMonitorValueCompleted));
+}
diff --git a/test/OperationMonitor/OperationMonitorTest.h b/test/OperationMonitor/OperationMonitorTest.h
new file mode 100644
index 0000000..f2349e7
--- /dev/null
+++ b/test/OperationMonitor/OperationMonitorTest.h
@@ -0,0 +1,37 @@
+/*
+ * 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>
+
+namespace AsteriskSCF
+{
+namespace OperationMonitorTests
+{
+
+class OperationMonitorTestSuite
+{
+public:
+    /**
+     * Registers the test suite with the global test suite. 
+     * There isn't anything else that needs to be done.
+     **/
+    OperationMonitorTestSuite();
+};
+
+} // namespace OperationMonitorTestSuite
+} // namespace AsteriskSCF 
diff --git a/test/UtilityTests.cpp b/test/UtilityTests.cpp
index 3c354e1..797b4d8 100644
--- a/test/UtilityTests.cpp
+++ b/test/UtilityTests.cpp
@@ -25,6 +25,7 @@
 #include "ProxyHelper/ProxyHelperTests.h"
 #include "LocatorRegistration/LocatorRegistrationTest.h"
 #include "OperationContextCache/OperationContextCacheTest.h"
+#include "OperationMonitor/OperationMonitorTest.h"
 
 #include <boost/test/unit_test.hpp>
 #include <boost/bind.hpp>
@@ -63,6 +64,7 @@ public:
         char** argv = mArgs.argv();
 
         OperationContextCacheTests::OperationContextCacheTestSuite operationContextTest;
+        OperationMonitorTests::OperationMonitorTestSuite operationMonitorTests;
         PropertyHelperTests::PropertyHelperTestSuite propertyTests(mCommunicator);
         ProxyHelperTests::ProxyHelperTestSuite proxyHelperTests(mCommunicator);
         LocatorRegistrationTests::LocatorRegistrationTestSuite locatorWrapperTest(mCommunicator);

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


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



More information about the asterisk-scf-commits mailing list