[asterisk-scf-commits] asterisk-scf/release/bridging.git branch "master" updated.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Fri Sep 30 12:44:25 CDT 2011


branch "master" has been updated
       via  19496522bf61f9a2805b5e7fc895909634b9a50e (commit)
      from  649687f8e6d0723c82155cf25b7f2fbe014b6517 (commit)

Summary of changes:
 .../BridgeService/BridgeReplicatorIf.ice           |    9 +-
 src/BridgeCreationExtensionPointImpl.cpp           |  141 ++++++++++++++++
 src/BridgeCreationExtensionPointImpl.h             |   54 ++++++
 src/BridgeImpl.cpp                                 |   55 ++++--
 src/BridgeImpl.h                                   |    8 +-
 src/BridgeManagerImpl.cpp                          |  174 ++++++++++++++++++--
 src/BridgeManagerImpl.h                            |    3 +-
 src/CMakeLists.txt                                 |    2 +
 src/Component.cpp                                  |    8 +-
 test/BridgeListenerI.h                             |    1 +
 test/CMakeLists.txt                                |    2 +-
 test/TestBridging.cpp                              |  157 +++++++++++++++++-
 12 files changed, 571 insertions(+), 43 deletions(-)
 create mode 100755 src/BridgeCreationExtensionPointImpl.cpp
 create mode 100755 src/BridgeCreationExtensionPointImpl.h


- Log -----------------------------------------------------------------
commit 19496522bf61f9a2805b5e7fc895909634b9a50e
Author: Brent Eagles <beagles at digium.com>
Date:   Fri Sep 30 15:14:06 2011 -0230

    bridge creation extension point support

diff --git a/slice/AsteriskSCF/Replication/BridgeService/BridgeReplicatorIf.ice b/slice/AsteriskSCF/Replication/BridgeService/BridgeReplicatorIf.ice
index fb0b7ec..0eb53de 100644
--- a/slice/AsteriskSCF/Replication/BridgeService/BridgeReplicatorIf.ice
+++ b/slice/AsteriskSCF/Replication/BridgeService/BridgeReplicatorIf.ice
@@ -163,7 +163,6 @@ enum ServiceState
     Destroyed
 };
 sequence<AsteriskSCF::SessionCommunications::V1::BridgeManagerListener*> BridgeManagerListenerSeq;
-sequence<AsteriskSCF::SessionCommunications::V1::BridgeListener*> BridgeListenerSeq;
     
 /**
  * The bridge manager state.
@@ -171,7 +170,7 @@ sequence<AsteriskSCF::SessionCommunications::V1::BridgeListener*> BridgeListener
 class BridgeManagerStateItem extends ReplicatedStateItem
 {
     ServiceState runningState;
-    BridgeListenerSeq defaultBridgeListeners;
+    AsteriskSCF::SessionCommunications::V1::BridgeListenerSeq defaultBridgeListeners;
     BridgeManagerListenerSeq listeners;
 };
 
@@ -187,6 +186,12 @@ class BridgeStateItem extends ReplicatedStateItem
     string bridgeId;     
 
     /**
+     * The proxy that the bridge should "publish" through events. This 
+     * provides a mechanism to supported decorated bridges. 
+     */
+    AsteriskSCF::SessionCommunications::V1::Bridge* publishedBridge;
+
+    /**
      * The current activation state of the bridge. NOT the same
      * as the Component running state.
      **/
diff --git a/src/BridgeCreationExtensionPointImpl.cpp b/src/BridgeCreationExtensionPointImpl.cpp
new file mode 100755
index 0000000..6a4ab31
--- /dev/null
+++ b/src/BridgeCreationExtensionPointImpl.cpp
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+#include "BridgeCreationExtensionPointImpl.h"
+#include <boost/thread/shared_mutex.hpp>
+#include "BridgeServiceConfig.h"
+
+using namespace AsteriskSCF::BridgeService;
+using namespace AsteriskSCF::SessionCommunications::V1;
+using namespace AsteriskSCF::SessionCommunications::ExtensionPoints::V1;
+using namespace AsteriskSCF::System::Logging;
+using namespace AsteriskSCF::System::Hook::V1;
+
+namespace 
+{
+    class BridgeExtPtImpl : public BridgeCreationExtensionPointImpl 
+    {
+    public:
+        BridgeExtPtImpl(const Logger& logger) :
+            mLogger(logger)
+        {
+        }
+
+        void addHook(const BridgeCreationHookPrx& newHook, const Ice::Current& current)
+        {
+            UniqueLock lock(mLock);
+            BridgeCreationHookSeq::iterator i = 
+                find_if(mHooks.begin(), mHooks.end(), IdentityComparePredicate<BridgeCreationHookPrx>(newHook));
+            if (i != mHooks.end())
+            {
+                mLogger(Debug) << "refreshing creation hook " << newHook << " on " 
+                    << objectIdFromCurrent(current);
+                //
+                // Refresh the proxy if it is already in the vector.
+                // 
+                *i = newHook;
+            }
+            else
+            {
+                mLogger(Debug) << "adding creation hook " << newHook << " on " 
+                    << objectIdFromCurrent(current);
+                mHooks.push_back(newHook);
+            }
+        }
+
+        void removeHook(const BridgeCreationHookPrx& hookToRemove, const Ice::Current& current)
+        {
+            UniqueLock lock(mLock);
+            mLogger(Debug) << "removing creation hook " << hookToRemove << " on " 
+                << objectIdFromCurrent(current);
+            mHooks.erase(remove_if(mHooks.begin(), mHooks.end(), 
+                    IdentityComparePredicate<BridgeCreationHookPrx>(hookToRemove)), mHooks.end());
+        }
+
+        void clearHooks(const Ice::Current& current)
+        {
+            UniqueLock lock(mLock);
+            mLogger(Debug) << "clearing hooks from " << objectIdFromCurrent(current);
+            mHooks.clear();
+        }
+
+        BridgeCreationHookDataPtr runHooks(const BridgeCreationHookDataPtr& originalData)
+        {
+            mLogger(Debug) << "executing hooks";
+            BridgeCreationHookSeq hooks = getHooks();
+            BridgeCreationHookSeq deadHooks;
+            BridgeCreationHookDataPtr tokenData = BridgeCreationHookDataPtr::dynamicCast(originalData->ice_clone());
+            for (BridgeCreationHookSeq::const_iterator i = hooks.begin(); i != hooks.end(); ++i)
+            {
+                try
+                {
+                    BridgeCreationHookDataPtr resultData; 
+                    HookResult result = (*i)->execute(tokenData, resultData);
+                    if (result.status == AsteriskSCF::System::Hook::V1::Succeeded)
+                    {
+                        tokenData = resultData;
+                    }
+                }
+                catch (const Ice::ObjectNotExistException&)
+                {
+                    mLogger(Debug) << "received ONE when running hook " << (*i) << ", removing from list";
+                    deadHooks.push_back(*i);
+                }
+                catch (const std::exception& ex)
+                {
+                    mLogger(Debug) << ex.what() << " thrown when executing bridge creation hook " << (*i) << ", skipping";
+                }
+            }
+            removeHooks(deadHooks);
+            return tokenData;
+        }
+
+    private:
+        typedef boost::shared_lock<boost::shared_mutex> SharedLock;
+        typedef boost::unique_lock<boost::shared_mutex> UniqueLock;
+        boost::shared_mutex mLock;
+
+        Logger mLogger;
+        BridgeCreationHookSeq mHooks;
+
+        void removeHooks(const BridgeCreationHookSeq& hooks)
+        {
+            if (hooks.empty())
+            {
+                return;
+            }
+
+            UniqueLock lock(mLock);
+            for (BridgeCreationHookSeq::const_iterator i = hooks.begin(); i != hooks.end(); ++i)
+            {
+                mHooks.erase(remove_if(mHooks.begin(), mHooks.end(), 
+                        IdentityComparePredicate<BridgeCreationHookPrx>(*i)), mHooks.end());
+            }
+        }
+
+        BridgeCreationHookSeq getHooks()
+        {
+            SharedLock lock(mLock);
+            return mHooks;
+        }
+    };
+};
+
+AsteriskSCF::BridgeService::BridgeCreationExtensionPointImplPtr 
+AsteriskSCF::BridgeService::BridgeCreationExtensionPointImpl::create(const Logger& logger)
+{
+    return new BridgeExtPtImpl(logger);
+}
diff --git a/src/BridgeCreationExtensionPointImpl.h b/src/BridgeCreationExtensionPointImpl.h
new file mode 100755
index 0000000..5cc6c6a
--- /dev/null
+++ b/src/BridgeCreationExtensionPointImpl.h
@@ -0,0 +1,54 @@
+/*
+ * 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/SessionCommunications/SessionCommunicationsExtensionPointsIf.h>
+
+namespace AsteriskSCF
+{
+
+//
+// Forward declarations.
+//
+namespace System
+{
+namespace Logging
+{
+
+class Logger;
+
+} /* End of namespace Logging */
+} /* End of namespace System */
+
+namespace BridgeService
+{
+    /**
+     * Base class for internal methods.
+     */
+    class BridgeCreationExtensionPointImpl : public AsteriskSCF::SessionCommunications::ExtensionPoints::V1::BridgeCreationExtensionPoint
+    {
+    public:
+
+        virtual AsteriskSCF::SessionCommunications::ExtensionPoints::V1::BridgeCreationHookDataPtr runHooks(
+            const AsteriskSCF::SessionCommunications::ExtensionPoints::V1::BridgeCreationHookDataPtr& originalData) = 0;
+
+        static IceUtil::Handle<BridgeCreationExtensionPointImpl> 
+            create(const AsteriskSCF::System::Logging::Logger&);
+    };
+    typedef IceUtil::Handle<BridgeCreationExtensionPointImpl> BridgeCreationExtensionPointImplPtr;
+
+} // End of namespace Bridging.
+} // End of namespace AsteriskSCF.
diff --git a/src/BridgeImpl.cpp b/src/BridgeImpl.cpp
index 5f85479..edcd46b 100755
--- a/src/BridgeImpl.cpp
+++ b/src/BridgeImpl.cpp
@@ -97,12 +97,17 @@ public:
     BridgeCookies getCookies(const BridgeCookies& cookies, const Ice::Current&);
 
     //
+    // Internal use variant of setCookies.
+    //
+    void setCookiesImpl(const BridgeCookies& cookies);
+
+    //
     // BridgeServant methods
     //
     bool destroyed();
     void destroyImpl();
     void shutdownImpl(const Ice::Current& current);
-    void activate(const BridgePrx& proxy);
+    void activate(const BridgePrx& proxy, const std::string& id);
 
     void updateState(const BridgeStateItemPtr& state);
     void addListener(const BridgeListenerStateItemPtr& update);
@@ -1040,13 +1045,7 @@ void BridgeImpl::setCookies(const BridgeCookies& cookies, const Ice::Current& cu
     BridgeStateItemPtr update;
     {
         boost::unique_lock<boost::shared_mutex> lock(mLock);
-        for (BridgeCookies::const_iterator i = cookies.begin(); i != cookies.end(); ++i)
-        {
-            if ((*i))
-            {
-                mState->cookies[(*i)->ice_id()] = (*i);
-            }
-        }
+        setCookiesImpl(cookies);
         if (!cookies.empty())
         {
             update = createUpdate();
@@ -1096,6 +1095,20 @@ BridgeCookies BridgeImpl::getCookies(const BridgeCookies& cookies, const Ice::Cu
     return result;
 }
 
+void BridgeImpl::setCookiesImpl(const BridgeCookies& cookies)
+{
+    // 
+    // This is only used for initial setting of cookies and will not be used after the object has been activated.
+    //
+    for (BridgeCookies::const_iterator i = cookies.begin(); i != cookies.end(); ++i)
+    {
+        if ((*i))
+        {
+            mState->cookies[(*i)->ice_id()] = (*i);
+        }
+    }
+}
+
 bool BridgeImpl::destroyed()
 {
     boost::shared_lock<boost::shared_mutex> lock(mLock);
@@ -1111,9 +1124,9 @@ void BridgeImpl::destroyImpl()
         mState->runningState = Destroyed;
         mSessions = 0;
 
-        if (mPrx)
+        if (mObjAdapter && mState)
         {
-            mObjAdapter->remove(mPrx->ice_getIdentity());
+            mObjAdapter->remove(mObjAdapter->getCommunicator()->stringToIdentity(mState->bridgeId));
         }
     }
     catch (const Ice::Exception&)
@@ -1139,14 +1152,14 @@ void BridgeImpl::shutdownImpl(const Ice::Current& current)
     shutdown(current);
 }
 
-void BridgeImpl::activate(const BridgePrx& proxy)
+void BridgeImpl::activate(const BridgePrx& proxy, const std::string& bridgeId)
 {
     mPrx = proxy;
-    string listenerId = mObjAdapter->getCommunicator()->identityToString(mPrx->ice_getIdentity());
-    mLogger(Trace) << FUNLOG << " : activating with " << listenerId;
-    mState->key = listenerId;
-    mState->bridgeId = listenerId;
-    listenerId += ".sessionListener";
+    mState->publishedBridge = proxy;
+    mState->key = bridgeId;
+    mState->bridgeId = bridgeId;
+    string listenerId = bridgeId + ".sessionListener"; 
+    mLogger(Debug) << FUNLOG << " : activating session listener with " << listenerId;
     mActivated = true;
     mSessionListenerPrx =
         SessionListenerPrx::uncheckedCast(
@@ -1194,8 +1207,14 @@ void BridgeImpl::activate()
     mLogger(Trace) << FUNLOG;
     boost::unique_lock<boost::shared_mutex> lock(mLock);
     mActivated = true;
-    mPrx = BridgePrx::uncheckedCast(mObjAdapter->add(this, mObjAdapter->getCommunicator()->stringToIdentity(mState->key)));
-    string listenerId = mState->key + ".sessionListener";
+    //
+    // XXX this is not correct with extension points... this could be a decorator.
+    //
+
+    mPrx = mState->publishedBridge;
+    BridgePrx actualPrx = BridgePrx::uncheckedCast(mObjAdapter->add(this, mObjAdapter->getCommunicator()->stringToIdentity(mState->key)));
+
+    string listenerId = mState->key + ".sessionListener"; // XXX this is no longer a derived thing.
     mSessionListenerPrx = SessionListenerPrx::uncheckedCast(
         mObjAdapter->add(mSessionListener, mObjAdapter->getCommunicator()->stringToIdentity(listenerId)));
     //
diff --git a/src/BridgeImpl.h b/src/BridgeImpl.h
index 2c9ab9f..35b311f 100644
--- a/src/BridgeImpl.h
+++ b/src/BridgeImpl.h
@@ -90,7 +90,8 @@ public:
      * ONCE per instance and is not thread safe.
      *
      **/
-    virtual void activate(const AsteriskSCF::SessionCommunications::V1::BridgePrx& proxy) = 0;
+    virtual void activate(const AsteriskSCF::SessionCommunications::V1::BridgePrx& proxy, 
+        const std::string& id) = 0;
 
     /**
      *
@@ -115,6 +116,11 @@ public:
     virtual void forceUpdate() = 0;
 
     /**
+     * Internal method for setting the cookies on a this servant.
+     */
+    virtual void setCookiesImpl(const AsteriskSCF::SessionCommunications::V1::BridgeCookies& cookies) =0;
+
+    /**
      *
      * For the BridgeManager or any object managing a bridge object! Gets a list of initialized tasks that will add the
      * provided sessions to the bridge object in a manner consistent with "Bridge::addSessions()".
diff --git a/src/BridgeManagerImpl.cpp b/src/BridgeManagerImpl.cpp
index 04089a2..d8a343d 100644
--- a/src/BridgeManagerImpl.cpp
+++ b/src/BridgeManagerImpl.cpp
@@ -24,6 +24,7 @@
 #include "BridgeImpl.h"
 #include "BridgeManagerListenerMgr.h"
 #include "BridgeReplicatorIf.h"
+#include "BridgeCreationExtensionPointImpl.h"
 #include <AsteriskSCF/System/ExceptionsIf.h>
 #include <AsteriskSCF/System/Component/ComponentServiceIf.h>
 
@@ -35,11 +36,44 @@ using namespace AsteriskSCF::SessionCommunications::V1;
 using namespace AsteriskSCF::Core::Discovery::V1;
 using namespace AsteriskSCF::BridgeService;
 using namespace AsteriskSCF::Replication::BridgeService::V1;
+using namespace AsteriskSCF::SessionCommunications::ExtensionPoints::V1;
 using namespace std;
 
 namespace 
 {
 
+#ifndef _NDEBUG
+void dump(const Logger& logger, const BridgeCreationHookDataPtr& hookData)
+{
+    ostringstream os;
+    os << "Hook data:";
+    string indent = "   ";
+    string prefix = "\n";
+    os <<  prefix << indent << "decorator/original proxy: " << hookData->bridge;
+    os <<  prefix << indent << "listeners (" << hookData->listeners.size() << ')';
+
+    for (BridgeListenerSeq::const_iterator i = hookData->listeners.begin(); i != hookData->listeners.end(); ++i)
+    {
+        os << prefix << indent << indent << *i;
+    }
+    os <<  prefix << indent << "cookies (" << hookData->cookies.size() << ')';
+    for (BridgeCookies::const_iterator i = hookData->cookies.begin(); i != hookData->cookies.end(); ++i)
+    {
+        os << prefix << indent << indent << (*i)->ice_id();
+    }
+    os <<  prefix << indent << "sessions (" << hookData->initialSessions.size() << ')';
+    for (SessionSeq::const_iterator i = hookData->initialSessions.begin(); i != hookData->initialSessions.end(); ++i)
+    {
+        os << prefix << indent << indent << (*i);
+    }
+    logger(Debug) << os.str();
+}
+#else
+void dump(const Logger&, const BridgeCreationHookDataPtr&)
+{
+}
+#endif
+
 class BridgeManagerImpl : public BridgeManagerServant
 {
 public:
@@ -67,6 +101,7 @@ public:
     {
         BridgeServantPtr servant;
         BridgePrx proxy;
+        BridgePrx decoratingPrx;
     };
 
     bool destroyed();
@@ -77,7 +112,7 @@ public:
 
     vector<BridgeServantPtr> getBridges();
     
-    void activate();
+    void activate(const ServiceLocatorManagementPrx& locator);
 
     string getID()
     {
@@ -99,6 +134,10 @@ private:
     BridgeManagerListenerMgrPtr mListeners;
     Logger mLogger;
 
+    BridgeCreationExtensionPointImplPtr mCreationExtension;
+    BridgeCreationExtensionPointPrx mCreationExtensionPrx;
+    ServiceManagementPrx mCreationExtensionPointServicePrx;
+
     BridgeManagerStateItemPtr mState;
 
     void reap();
@@ -154,6 +193,7 @@ protected:
         {
             mListenerMgr->bridgeCreated(mBridgeProxy);
         }
+        
         mCallback->ice_response(mBridgeProxy);
         return true;
     }
@@ -182,30 +222,99 @@ void BridgeManagerImpl::createBridge_async(const AMD_BridgeManager_createBridgeP
         string stringId = string("bridge.") + IceUtil::generateUUID();
         Ice::Identity id(mAdapter->getCommunicator()->stringToIdentity(stringId));
         BridgePrx prx(BridgePrx::uncheckedCast(mAdapter->createProxy(id)));
-        BridgeListenerMgrPtr mgr(new BridgeListenerMgr(mAdapter->getCommunicator(), stringId, prx));
-        vector<BridgeListenerPrx> listeners(mState->defaultBridgeListeners);
+        AsteriskSCF::SessionCommunications::V1::BridgeListenerSeq listeners(mState->defaultBridgeListeners);
         if (listener)
         {
             listeners.push_back(listener);
         }
 
+        //
+        // "sessions" is a const, so we need to make a local non-const copy that can be modified
+        // by the hooks if need be.
+        //
+        SessionSeq initialSessions(sessions);
+
+        //
+        // We create a local outside of the block that initializes and runs the hooks if they are
+        // present. If this is '0' later on in the code, it signifies the bridge creation extension
+        // point mechanism was not initialized.
+        //
+        BridgeCreationHookDataPtr hookData;
+        BridgeInfo info;
+        info.proxy = prx;
+        if (mCreationExtension)
+        {
+            //
+            // Set up hook data with initial values and run the hooks!
+            //
+            hookData = new BridgeCreationHookData;
+            hookData->bridge = prx;
+            hookData->listeners = listeners;
+            hookData->initialSessions = sessions;
+            hookData = mCreationExtension->runHooks(hookData);
+
+            //
+            // Update locals with the result of running the hooks.
+            //
+            listeners = hookData->listeners;
+            initialSessions = hookData->initialSessions;
+            info.decoratingPrx = hookData->bridge;
+            dump(mLogger, hookData);
+        }
+        
+        //
+        // The bridge listener manager is a wrapper/helper class that manages the listeners and
+        // propogates the bridge events. We separate it's instantiation from the construction
+        // of the bridge itself as this is a natural area of refinement and extension.
+        //
+        BridgeListenerMgrPtr mgr(new BridgeListenerMgr(mAdapter->getCommunicator(), stringId, info.decoratingPrx));
+
+        //
+        // Now we can get down to the creation of the bridge servant itself. Note that the 
+        // initialization is still not really complete as we need to set up and cookies,
+        // initial sessions, etc that may have been defined or added as part of the createBridge
+        // call or the bridge creation hooks.
+        //
         BridgeServantPtr bridge = BridgeServant::create(stringId, mAdapter, listeners, mgr, mReplicationContext->getReplicator(), mLogger);
+
         Ice::ObjectPrx obj = mAdapter->add(bridge, id);
 
         mLogger(Info) << objectIdFromCurrent(current) << ": creating new bridge " << obj->ice_toString() << "." ;
-        BridgeInfo info;
+
+        //
+        // Finish updating BridgeInfo struct.
+        //
         info.servant = bridge;
-        info.proxy = BridgePrx::uncheckedCast(obj);
-        bridge->activate(info.proxy);
+       
+        //
+        // It's very important to note that the bridge servant will not have it's own proxy!
+        // NOTE: This method is probably misnamed and misleading. The bridge servant was added to 
+        // object adapter above. It might be a better idea to move adding the servant to the adapter
+        // into the activate method.
+        // 
+        bridge->activate(info.decoratingPrx, stringId);
         mBridges.push_back(info);
 
+        if (hookData)
+        {
+            bridge->setCookiesImpl(hookData->cookies);
+        }
+
+        //
+        // There are some finalization tasks that may be performed asynchronously (replication etc.)
+        //
         QueuedTasks tasks;
-        if (!sessions.empty())
+
+        //
+        // If there are some sessions that need to be added to the bridge immediately
+        // upon creation, create some tasks to add to the queue.
+        //
+        if (!initialSessions.empty())
         {
-            bridge->getAddSessionsTasks(tasks, sessions);
+            bridge->getAddSessionsTasks(tasks, initialSessions);
         }
-        
-        tasks.push_back(new FinishUp(callback, mListeners, info.proxy));
+
+        tasks.push_back(new FinishUp(callback, mListeners, info.decoratingPrx));
         ExecutorPtr runner(new Executor(tasks, mLogger));
         runner->start();
     }
@@ -326,6 +435,17 @@ void BridgeManagerImpl::shutdown(const Ice::Current& current)
     {
         mListeners->stopped();
     }
+    try
+    {
+        if (mCreationExtensionPointServicePrx)
+        {
+            mCreationExtensionPointServicePrx->unregister();
+        }
+    }
+    catch (const std::exception& ex)
+    {
+        mLogger(Debug) << ex.what() << " caught while shutting down and unregistering supporting services.";
+    }
     mAdapter->getCommunicator()->shutdown();
     mState->runningState = AsteriskSCF::Replication::BridgeService::V1::Destroyed;
 }
@@ -371,13 +491,39 @@ vector<BridgeServantPtr> BridgeManagerImpl::getBridges()
     return result;
 }
 
-void BridgeManagerImpl::activate()
+void BridgeManagerImpl::activate(const AsteriskSCF::Core::Discovery::V1::ServiceLocatorManagementPrx& locator)
 {
-    boost::unique_lock<boost::shared_mutex> lock(mLock);
-    for (BridgeManagerListenerSeq::iterator i = mState->listeners.begin(); i != mState->listeners.end(); ++i)
     {
-        mListeners->addListener(*i);
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        if (mCreationExtension)
+        {
+            return;
+        }
+
+        for (BridgeManagerListenerSeq::iterator i = mState->listeners.begin(); i != mState->listeners.end(); ++i)
+        {
+            mListeners->addListener(*i);
+        }
+        mCreationExtension = BridgeCreationExtensionPointImpl::create(mLogger);
     }
+    Ice::Identity myId = mAdapter->getCommunicator()->stringToIdentity(mName);
+
+    //
+    // Incarnated as a facet as a convenience. Also added to the service locator though, so all is fine with our
+    // requirements vis-a-vis "good objects".
+    //
+    mCreationExtensionPrx = 
+        BridgeCreationExtensionPointPrx::uncheckedCast(mAdapter->addFacet(mCreationExtension, myId, BridgeCreationExtensionPointFacet));
+
+    string extPtId = IceUtil::generateUUID();
+
+    // Configure how other components look this component up.
+    ServiceLocatorParamsPtr params = new ServiceLocatorParams;
+    params->category = BridgeCreationExtensionPointCategory;
+    params->service = extPtId;
+   
+    mCreationExtensionPointServicePrx = locator->addService(mCreationExtensionPrx, extPtId);
+    mCreationExtensionPointServicePrx->addLocatorParams(params, "");
 }
 
 void BridgeManagerImpl::createBridgeReplica(const BridgeStateItemPtr& state)
diff --git a/src/BridgeManagerImpl.h b/src/BridgeManagerImpl.h
index 62090a2..163d5df 100644
--- a/src/BridgeManagerImpl.h
+++ b/src/BridgeManagerImpl.h
@@ -17,6 +17,7 @@
 
 #include <Ice/Ice.h>
 #include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
+#include <AsteriskSCF/Core/Discovery/ServiceLocatorIf.h>
 #include <AsteriskSCF/logger.h>
 #include <string>
 #include <vector>
@@ -49,7 +50,7 @@ public:
 
     virtual std::vector<BridgeServantPtr> getBridges() = 0;
 
-    virtual void activate() = 0;
+    virtual void activate(const AsteriskSCF::Core::Discovery::V1::ServiceLocatorManagementPrx&) = 0;
 
     virtual std::string getID() = 0;
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c7fbc72..839fd48 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,8 @@ astscf_component_add_files(bridgeservice SessionCollection.cpp)
 astscf_component_add_files(bridgeservice SessionCollection.h)
 astscf_component_add_files(bridgeservice SessionOperations.cpp)
 astscf_component_add_files(bridgeservice SessionOperations.h)
+astscf_component_add_files(bridgeservice BridgeCreationExtensionPointImpl.cpp) 
+astscf_component_add_files(bridgeservice BridgeCreationExtensionPointImpl.h) 
 astscf_component_add_files(bridgeservice ServiceUtil.h)
 astscf_component_add_files(bridgeservice DebugUtil.h)
 astscf_component_add_files(bridgeservice MediaSplicer.h)
diff --git a/src/Component.cpp b/src/Component.cpp
index 41f7d7f..595011a 100644
--- a/src/Component.cpp
+++ b/src/Component.cpp
@@ -99,13 +99,17 @@ void Component::onPostInitialize()
 {
     if (getReplicationContext()->isActive())
     {
-       mBridgeManager->activate(); 
+        mBridgeManager->activate(getServiceLocatorManagement()); 
     }
 }
 
 void Component::onActivated()
 {
-    mBridgeManager->activate(); // TBD...Is this really needed? Is there really no standby() correlary?
+    mBridgeManager->activate(getServiceLocatorManagement()); // TBD...Is this really needed? Is there really no standby() correlary?
+    // 
+    // Response to TBD. None of the AsteriskSCF components support moving from active to standby.. the presumption
+    // being that if you are active, the only way you are going to be moved to standby is if you are restarted.
+    //
 }
 
 void Component::onPreInitialize()
diff --git a/test/BridgeListenerI.h b/test/BridgeListenerI.h
index 05f12b9..7040486 100644
--- a/test/BridgeListenerI.h
+++ b/test/BridgeListenerI.h
@@ -55,6 +55,7 @@ public:
 private:
     bool mShuttingDown;
     bool mStopped;
+    bool mStopping;
 
     IceUtil::Monitor<IceUtil::Mutex> mAddMonitor;
     IceUtil::Monitor<IceUtil::Mutex> mRemoveMonitor;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 6f2f1af..9773c64 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -26,11 +26,11 @@ target_link_libraries(bridge_component_test logging-client)
 astscf_test_icebox(bridge_component_test config/test_bridging.conf)
 
 astscf_component_init(bridge_unit_tests)
-astscf_component_add_slices(bridge_unit_tests PROJECT AsteriskSCF/Replication/BridgeService/BridgeReplicatorIf.ice)
 astscf_component_add_files(bridge_unit_tests ../src/SessionCollection.cpp)
 astscf_component_add_files(bridge_unit_tests ../src/SessionOperations.cpp)
 astscf_component_add_files(bridge_unit_tests ../src/SessionWrapper.cpp)
 astscf_component_add_files(bridge_unit_tests ../src/MediaSplicer.cpp)
+astscf_component_add_slices(bridge_unit_tests PROJECT AsteriskSCF/Replication/BridgeService/BridgeReplicatorIf.ice)
 astscf_component_add_files(bridge_unit_tests UnitTests.cpp)
 astscf_component_add_ice_libraries(bridge_unit_tests Ice)
 astscf_component_add_boost_libraries(bridge_unit_tests unit_test_framework thread)
diff --git a/test/TestBridging.cpp b/test/TestBridging.cpp
index f988c68..b7efa3f 100644
--- a/test/TestBridging.cpp
+++ b/test/TestBridging.cpp
@@ -20,6 +20,7 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/test/debug.hpp>
 #include <AsteriskSCF/SessionCommunications/SessionCommunicationsIf.h>
+#include <AsteriskSCF/SessionCommunications/SessionCommunicationsExtensionPointsIf.h>
 #include <AsteriskSCF/Media/MediaIf.h>
 #include <AsteriskSCF/System/Component/ReplicaIf.h>
 #include <IceUtil/UUID.h>
@@ -40,6 +41,7 @@
 
 using namespace AsteriskSCF::BridgingTest;
 using namespace AsteriskSCF::SessionCommunications::V1;
+using namespace AsteriskSCF::SessionCommunications::ExtensionPoints::V1;
 using namespace AsteriskSCF::Core::Discovery::V1;
 using namespace AsteriskSCF::Core::Routing::V1;
 using namespace AsteriskSCFTest;
@@ -50,6 +52,48 @@ using namespace std;
 namespace
 {
 
+class TestCreationHook : public BridgeCreationHook
+{
+public:
+
+    void addCookies(const BridgeCookies& cookies)
+    {
+        mCookies = cookies;
+    }
+
+    void addListeners(const BridgeListenerSeq& listeners)
+    {
+        mListeners = listeners;
+    }
+    
+    void addSessions(const SessionSeq& sessions)
+    {
+        mSessions = sessions;
+    }
+
+    void setResult(AsteriskSCF::System::Hook::V1::HookResult resultValue)
+    {
+        mResult = resultValue;
+    }
+
+    AsteriskSCF::System::Hook::V1::HookResult execute(const BridgeCreationHookDataPtr& originalData, 
+        BridgeCreationHookDataPtr& newData, const Ice::Current&)
+    {
+        newData = BridgeCreationHookDataPtr::dynamicCast(originalData->ice_clone());
+        newData->cookies.insert(newData->cookies.end(), mCookies.begin(), mCookies.end());
+        newData->listeners.insert(newData->listeners.end(), mListeners.begin(), mListeners.end());
+        newData->initialSessions.insert(newData->initialSessions.end(), mSessions.begin(), mSessions.end());
+        return mResult;
+    }
+
+private:
+    BridgeCookies mCookies;
+    BridgeListenerSeq mListeners;
+    SessionSeq mSessions;
+    AsteriskSCF::System::Hook::V1::HookResult mResult;
+};
+typedef IceUtil::Handle<TestCreationHook> TestCreationHookPtr;
+
 BridgeCookies bakeTestCookies()
 {
     BridgeCookies result;
@@ -935,7 +979,7 @@ public:
                 //
                 mgrPrx->listBridges();
 
-                BOOST_CHECK(servant->createCalls() == 1);
+                BOOST_CHECK(servant->createCalls() == 1); 
                 mgrPrx->removeListener(listenerPrx);
                 
                 bridge = mgrPrx->createBridge(sessions, 0);
@@ -1075,13 +1119,12 @@ public:
                 returnedCookies = cookieMap["sessionsRemoved"];
                 tasteCookies(returnedCookies);
 
-                BOOST_REQUIRE(bridgeListener->waitForStopped(5000));
+                BOOST_REQUIRE(bridgeListener->waitForStopping(5000));
                 cookieMap = bridgeListener->getCookieMap();
                 BOOST_REQUIRE(cookieMap.find("stopping") != cookieMap.end());
                 returnedCookies = cookieMap["stopping"];
                 tasteCookies(returnedCookies);
-                BOOST_REQUIRE(cookieMap.find("stopped") != cookieMap.end());
-                returnedCookies = cookieMap["stopped"];
+                BOOST_REQUIRE(bridgeListener->waitForStopped(5000));
                 BOOST_REQUIRE(!returnedCookies.empty());
                 tasteCookies(returnedCookies);
                 returnedCookies = bridge->getCookies(cookies);
@@ -1204,6 +1247,110 @@ public:
         }
     }
 
+    void extensionPointTest()
+    {
+        try
+        {
+            IceEnvironment testEnv(env()->properties());
+            try
+            {
+                Ice::ObjectAdapterPtr testAdapter =  testEnv.communicator()->createObjectAdapter("TestUtilAdapter");
+                testAdapter->activate();
+                BridgeManagerListenerIPtr servant = new BridgeManagerListenerI;
+                AsteriskSCF::SessionCommunications::V1::BridgeManagerListenerPrx listenerPrx;
+                addServant(listenerPrx, testAdapter, servant, testEnv.strToIdent(IceUtil::generateUUID()));
+
+                AsteriskSCF::SessionCommunications::V1::BridgeManagerPrx mgrPrx = env()->primaryBridgeManager();
+                BOOST_CHECK(mgrPrx);
+                mgrPrx->addListener(listenerPrx);
+                BOOST_CHECK(servant->stoppingCalls() == 0);
+                BOOST_CHECK(servant->stoppedCalls() == 0);
+                BOOST_CHECK(servant->createCalls() == 0);
+
+                AsteriskSCF::SessionCommunications::ExtensionPoints::V1::BridgeCreationExtensionPointPrx 
+                    extPoint = AsteriskSCF::SessionCommunications::ExtensionPoints::V1::
+                    BridgeCreationExtensionPointPrx::checkedCast(mgrPrx,
+                        AsteriskSCF::SessionCommunications::ExtensionPoints::V1::BridgeCreationExtensionPointFacet);
+                BOOST_REQUIRE(extPoint);
+
+                TestCreationHookPtr hook(new TestCreationHook);
+                AsteriskSCF::SessionCommunications::ExtensionPoints::V1::BridgeCreationHookPrx hookPrx;
+                addServant(hookPrx, testAdapter, hook, testEnv.strToIdent(IceUtil::generateUUID()));
+                extPoint->addHook(hookPrx);
+
+                TestChannelWrapper channel(env()->properties());
+                AsteriskSCF::SessionCommunications::V1::SessionSeq sessions;
+                AsteriskSCF::SessionCommunications::V1::SessionPrx a = channel.getSession("311");
+                AsteriskSCF::SessionCommunications::V1::SessionPrx b = channel.getSession("312");
+                sessions.push_back(a);
+                sessions.push_back(b);
+                hook->addSessions(sessions);
+                sessions.clear();
+
+                AsteriskSCF::BridgingTest::BridgeListenerPtr bridgeListener = new BridgeListenerI;
+                AsteriskSCF::SessionCommunications::V1::BridgeListenerPrx bridgeListenerPrx;
+                addServant(bridgeListenerPrx, testAdapter, bridgeListener, testEnv.strToIdent(IceUtil::generateUUID()));
+                BridgeListenerSeq listeners;
+                listeners.push_back(bridgeListenerPrx);
+                hook->addListeners(listeners);
+
+                BridgeCookies testCookies = bakeTestCookies();
+                hook->addCookies(testCookies);
+
+                AsteriskSCF::SessionCommunications::V1::BridgePrx bridge(mgrPrx->createBridge(sessions, 0));
+
+                //
+                // precondition checks for test validity.
+                //
+                std::string idA = testEnv.communicator()->identityToString(a->ice_getIdentity());
+                std::string idB = testEnv.communicator()->identityToString(b->ice_getIdentity());
+                std::vector<std::string> log;
+                channel.commands()->getlog(idA, log);
+                BOOST_CHECK(!find(log, "start"));
+                channel.commands()->getlog(idB, log);
+                BOOST_CHECK(!find(log, "start"));
+
+                AsteriskSCF::SessionCommunications::V1::SessionSeq eventSessions;
+                BridgeCookies returnedCookies = bridge->getCookies(testCookies);
+                tasteCookies(returnedCookies);
+
+                sessions.push_back(b);
+                eventSessions.clear();
+                bridge->removeSessions(sessions);
+                BOOST_REQUIRE(bridgeListener->waitForRemoved(5000, eventSessions));
+                CookieMap cookieMap = bridgeListener->getCookieMap();
+                BOOST_REQUIRE(!cookieMap.empty());
+                BOOST_REQUIRE(cookieMap.find("sessionsRemoved") != cookieMap.end());
+                returnedCookies = cookieMap["sessionsRemoved"];
+                tasteCookies(returnedCookies);
+
+                BOOST_REQUIRE(bridgeListener->waitForStopped(5000));
+                cookieMap = bridgeListener->getCookieMap();
+                BOOST_REQUIRE(cookieMap.find("stopping") != cookieMap.end());
+                returnedCookies = cookieMap["stopping"];
+                tasteCookies(returnedCookies);
+                BOOST_REQUIRE(cookieMap.find("stopped") != cookieMap.end());
+                returnedCookies = cookieMap["stopped"];
+                BOOST_REQUIRE(!returnedCookies.empty());
+                tasteCookies(returnedCookies);
+            }
+            catch (const Ice::Exception& ex)
+            {
+                std::ostringstream msg;
+                msg << "Unexpected Ice exception " << ex.what();
+                BOOST_FAIL(msg.str());
+            }
+            catch (...)
+            {
+                BOOST_FAIL("Unexpected exception");
+            }
+        }
+        catch (...)
+        {
+            BOOST_FAIL("Unexpected exception");
+        }
+    }
+
 private:
     TestEnvironmentPtr mTestEnvironment;
 };
@@ -1231,6 +1378,8 @@ bool init_unit_test()
         add(BOOST_TEST_CASE(boost::bind(&BridgeTester::simpleCookieAddTest, bridgeTester)));
     framework::master_test_suite().
         add(BOOST_TEST_CASE(boost::bind(&BridgeTester::cookieAddRemoveTest, bridgeTester)));
+    framework::master_test_suite().
+        add(BOOST_TEST_CASE(boost::bind(&BridgeTester::extensionPointTest, bridgeTester)));
     return true;
 }
 

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


-- 
asterisk-scf/release/bridging.git



More information about the asterisk-scf-commits mailing list