[asterisk-scf-commits] asterisk-scf/integration/sip.git branch "sip-configuration-refactor" created.

Commits to the Asterisk SCF project code repositories asterisk-scf-commits at lists.digium.com
Mon May 9 09:26:17 CDT 2011


branch "sip-configuration-refactor" has been created
        at  10098f0a139e0b275530a4bdc20e91ecb744d6f7 (commit)

- Log -----------------------------------------------------------------
commit 10098f0a139e0b275530a4bdc20e91ecb744d6f7
Author: Brent Eagles <beagles at digium.com>
Date:   Mon May 9 11:51:37 2011 -0230

    A refactoring of the configuration servant construction and implementation.
    The intent is to take the benefit of the visitor facility a bit further and
    use template code and function overloading to create reusable configuration
    patterns and separate object specific code from the visitor implementations
    themselves. In this refactoring example, the detailed visitor implementations
    are isolated enough that the could be put into source modules alongside
    the objects that are actually being configured.

diff --git a/src/PJSipManager.h b/src/PJSipManager.h
index d188e11..4a2f63a 100644
--- a/src/PJSipManager.h
+++ b/src/PJSipManager.h
@@ -109,6 +109,8 @@ private:
     bool setTransports(pjsip_endpoint *endpoint, const Ice::PropertiesPtr& props);
 };
 
+typedef boost::shared_ptr<PJSipManager> PJSipManagerPtr;
+
 }; //End namespace SipSessionManager
 
 }; //End namespace AsteriskSCF
diff --git a/src/SipConfiguration.cpp b/src/SipConfiguration.cpp
index 76fa596..fcf6012 100644
--- a/src/SipConfiguration.cpp
+++ b/src/SipConfiguration.cpp
@@ -29,34 +29,299 @@
 #include "SipEndpointFactory.h"
 #include "SipConfiguration.h"
 
+using namespace AsteriskSCF::SIP::V1;
+using namespace AsteriskSCF::System::Configuration::V1;
+using namespace AsteriskSCF::Core::Routing::V1;
+using namespace std;
+
+//
+// Note: the general group receives a default value in this refactoring no matter what, I suspect that this is actually
+// wrong and will address.
+//
+
 namespace AsteriskSCF
 {
 namespace SipSessionManager
 {
 
-using namespace AsteriskSCF::SIP::V1;
-using namespace AsteriskSCF::System::Configuration::V1;
-using namespace AsteriskSCF::Core::Routing::V1;
+template <class T>
+T createGroupTemplate(const T& group)
+{
+    T result = T::dynamicCast(group->ice_clone());
+    assert(result);
+    result->name = group->name;
+    return result;
+}
+
+template<>
+SipGeneralGroupPtr createGroupTemplate(const SipGeneralGroupPtr& source)
+{
+    return new SipGeneralGroup;
+}
+
+//
+// Specialization require since the name is different.
+//
+template <>
+SipDomainGroupPtr createGroupTemplate(const SipDomainGroupPtr& source)
+{
+    SipDomainGroupPtr r(new SipDomainGroup);
+    r->domain = source->domain;
+    return r;
+}
+
+static void performSerialCheck(const ConfigurationItemDict& changedItems, const ConfigurationItemDict& localItems)
+{
+    for (ConfigurationItemDict::const_iterator item = changedItems.begin();
+         item != changedItems.end();
+         ++item)
+    {
+        // If serial checking is to be skipped for this item just skip over it
+        if (item->second->serialNumber == -1)
+        {
+            continue;
+        }
+		
+        ConfigurationItemDict::const_iterator localItem = localItems.find(item->first);
+		
+        if (localItem == localItems.end())
+        {
+            // This is a new item so serial checking does not apply
+            continue;
+        }
+		
+        if (item->second->serialNumber < item->second->serialNumber)
+        {
+            //
+            // XXX Either throw an exception or log & remove the update!
+            //
+        }
+    }
+}
+
+class EndpointConfigHelper
+{
+    class Visitor : public SipConfigurationItemVisitor
+    {
+    public:
+        Visitor(const boost::shared_ptr<EndpointConfigHelper>& config) :
+          mConfig(config)
+        {
+        }
+
+        ~Visitor()
+        {
+            mConfig->updated();
+        }
+
+        void visitSipAllowableCallDirectionItem(const SipAllowableCallDirectionItemPtr& direction)
+        {
+            mConfig->update(direction);
+        }
+
+        void visitSipSourceTransportAddressItem(const SipSourceTransportAddressItemPtr& source)
+        {
+            mConfig->update(source);
+        }
+
+        void visitSipTargetDestinationAddressItem(const SipTargetDestinationAddressItemPtr& target)
+        {
+            mConfig->update(target);
+        };
+
+    private:
+        boost::shared_ptr<EndpointConfigHelper> mConfig;
+    };
+
+public:
+    EndpointConfigHelper(const SipEndpointPtr& endpoint, 
+        const boost::shared_ptr<SipEndpointFactory>& endpointFactory,
+        const AsteriskSCF::SmartProxy::SmartProxy<LocatorRegistryPrx>& registry,
+        const string& routingId) :
+      mEndpoint(endpoint),
+      mFactory(endpointFactory),
+      mRegistry(registry),
+      mRoutingId(routingId)
+    {
+    }
+
+    virtual ~EndpointConfigHelper()
+    {
+        //
+        // Doesn't really need to do anything at the moment.
+        //
+    }
+
+    SipConfigurationItemVisitorPtr getVisitor()
+    {
+        return new Visitor(boost::shared_ptr<EndpointConfigHelper>(this));
+    }
+
+    void update(const SipAllowableCallDirectionItemPtr& direction)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        enum Direction callDirection;
+        switch (direction->callDirection)
+        {
+        case Inbound:
+            callDirection = INBOUND;
+            break;
+        case Outbound:
+            callDirection = OUTBOUND;
+            break;
+        case Both:
+            callDirection = BOTH;
+            break;
+        default:
+            callDirection = NONE;
+        }
+        mEndpoint->setCallDirection(callDirection);
+    }
+
+    void update(const SipSourceTransportAddressItemPtr& source)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mEndpoint->setSourceAddress(source->host, source->port);
+    }
+
+    void update(const SipTargetDestinationAddressItemPtr& target)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mEndpoint->setTargetAddress(target->host, target->port);
+    }
+
+    void updated()
+    {
+        RegExSeq destinations;
+        mFactory->generateRoutingDestinations(destinations);
+        mRegistry->setEndpointLocatorDestinationIds(mRoutingId, destinations);
+    }
 
-class UDPTransportImplPriv
+private:
+    boost::shared_mutex mLock;
+    SipEndpointPtr mEndpoint;
+    boost::shared_ptr<SipEndpointFactory> mFactory;
+    AsteriskSCF::SmartProxy::SmartProxy<LocatorRegistryPrx> mRegistry;
+    string mRoutingId;
+};
+
+class ConfigBase
 {
 public:
+    virtual ~ConfigBase() {}
+
+    virtual SipConfigurationGroupPtr getGroup() const = 0;
+
+    virtual SipConfigurationItemVisitorPtr getVisitor() { return 0; }
+
+    virtual void updated() { }
+};
+typedef boost::shared_ptr<ConfigBase> ConfigBasePtr;
+    
+class UDPTransportConfig : public ConfigBase
+{
+    class Visitor : public SipConfigurationItemVisitor
+    {
+    public:
+        Visitor(const boost::shared_ptr<UDPTransportConfig>& config) :
+            mConfig(config)
+        {
+        }
+
+        ~Visitor()
+        {
+            mConfig->updated();
+        }
+
+        void visitSipHostItem(const SipHostItemPtr& hostItem)
+        {
+            mConfig->update(hostItem);
+        }
+    private:
+        boost::shared_ptr<UDPTransportConfig> mConfig;
+    };
+    
+public:
     /**
      * Constructor implementation for this
      */
-    UDPTransportImplPriv() : mTransport(0) { };
-    
+    UDPTransportConfig(const SipUDPTransportGroupPtr& group, PJSipManager* manager) :
+        mGroup(group),
+        mManager(manager),
+        mTransport(0),
+        mNeedsUpdating(false)
+    {
+    };
+
     /**
      * Destructor implementation that shuts down the transport gracefully if we go away
      */
-    ~UDPTransportImplPriv()
+    ~UDPTransportConfig()
     {
 	if (mTransport)
 	{
 	    pjsip_transport_shutdown(mTransport);
 	}
     };
-    
+
+    SipConfigurationItemVisitorPtr getVisitor()
+    {
+        return new Visitor(boost::shared_ptr<UDPTransportConfig>(this));
+    }
+
+    void update(const SipHostItemPtr& hostItem)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mNeedsUpdating = (mAddress != hostItem->host || mPort != hostItem->port);
+        if (mNeedsUpdating)
+        {
+            mAddress = hostItem->host;
+            mPort = hostItem->port;
+        }
+    }
+
+    void updated()
+    {
+        string hostname;
+        int port;
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            if (!mNeedsUpdating)
+            {
+                return;
+            }
+            mNeedsUpdating = false;
+            hostname = mAddress;
+            port = mPort;
+        }
+        
+        pjsip_transport *newTransport =  mManager->createUDPTransport(hostname, port);
+        pjsip_transport *oldTransport = 0;
+
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            oldTransport = mTransport;
+            mTransport = newTransport;
+        }
+
+        if (oldTransport)
+        {
+            pjsip_transport_shutdown(oldTransport);
+        }
+    }
+
+    SipConfigurationGroupPtr getGroup() const
+    {
+        return mGroup;
+    }
+        
+    SipUDPTransportGroupPtr getTypedGroup() const
+    {
+        return mGroup;
+    }
+private:
+    boost::shared_mutex mLock;
+
     /**
      * Address itself.
      */
@@ -70,32 +335,124 @@ public:
     /**
      * Configuration group itself.
      */
-    SipUDPTransportGroupPtr mGroup;
+    mutable SipUDPTransportGroupPtr mGroup;
     
     /**
      * Transport within pjsip.
      */
     pjsip_transport *mTransport;
+
+    PJSipManager* mManager;
+
+    bool mNeedsUpdating;
 };
+typedef boost::shared_ptr<UDPTransportConfig> UDPTransportConfigPtr;
+typedef std::map<std::string, UDPTransportConfigPtr> UDPTransportMap;
 
-class TCPTransportImplPriv
+class TCPTransportConfig : public ConfigBase
 {
+    class Visitor : public SipConfigurationItemVisitor
+    {
+    public:
+        Visitor(const boost::shared_ptr<TCPTransportConfig>& config) :
+            mConfig(config)
+        {
+        }
+
+        ~Visitor()
+        {
+            mConfig->updated();
+        }
+
+        void visitSipHostItem(const SipHostItemPtr& hostItem)
+        {
+            mConfig->update(hostItem);
+        }
+    private:
+        boost::shared_ptr<TCPTransportConfig> mConfig;
+    };
+    
 public:
     /**
      * Constructor implementation for this
      */
-    TCPTransportImplPriv() : mTransportFactory(0) { };
+    TCPTransportConfig(const SipTCPTransportGroupPtr& group, PJSipManager* manager) :
+        mGroup(group),
+        mManager(manager),
+        mTransportFactory(0),
+        mNeedsUpdating(false)
+    {
+    };
 
     /**
      * Destructor implementation that shuts down the transport gracefully if we go away
      */
-    ~TCPTransportImplPriv()
+    ~TCPTransportConfig()
     {
         if (mTransportFactory)
         {
             // I hope in the future it will be possible to shut down TCP based transports but for now... it is not
         }
     };
+    
+    SipConfigurationItemVisitorPtr getVisitor()
+    {
+        return new Visitor(boost::shared_ptr<TCPTransportConfig>(this));
+    }
+
+    void update(const SipHostItemPtr& hostItem)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mNeedsUpdating = (mAddress != hostItem->host || mPort != hostItem->port);
+        if (mNeedsUpdating)
+        {
+            mAddress = hostItem->host;
+            mPort = hostItem->port;
+        }
+    }
+
+    void updated()
+    {
+        string hostname;
+        int port;
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            if (!mNeedsUpdating)
+            {
+                return;
+            }
+            mNeedsUpdating = false;
+            hostname = mAddress;
+            port = mPort;
+        }
+        
+        pjsip_tpfactory* newTransportFactory =  mManager->createTCPTransport(hostname, port);
+        pjsip_tpfactory* oldTransport = 0;
+
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            oldTransport = mTransportFactory;
+            mTransportFactory = newTransportFactory;
+        }
+
+        //
+        // XXX and now it would be nice if we could do something with the transport.
+        //
+        oldTransport = 0;
+    }
+
+    SipConfigurationGroupPtr getGroup() const
+    {
+        return mGroup;
+    }
+    
+    SipTCPTransportGroupPtr getTypedGroup() const
+    {
+        return mGroup;
+    }
+
+private:
+    boost::shared_mutex mLock;
 
     /**
      * Address itself.
@@ -110,26 +467,75 @@ public:
     /**
      * Configuration group itself.
      */
-    SipTCPTransportGroupPtr mGroup;
+    mutable SipTCPTransportGroupPtr mGroup;
+
+    PJSipManager* mManager;
 
     /**
      * Transport factory within pjsip.
      */
     pjsip_tpfactory *mTransportFactory;
+
+    bool mNeedsUpdating;
 };
+typedef boost::shared_ptr<TCPTransportConfig> TCPTransportConfigPtr;
+typedef std::map<std::string, TCPTransportConfigPtr> TCPTransportMap;
 
-class TLSTransportImplPriv
+class TLSTransportConfig : public ConfigBase
 {
+    class Visitor : public SipConfigurationItemVisitor
+    {
+    public:
+        Visitor(const boost::shared_ptr<TLSTransportConfig>& config) :
+            mConfig(config)
+        {
+        }
+
+        ~Visitor()
+        {
+            mConfig->updated();
+        }
+
+        void visitSipHostItem(const SipHostItemPtr& hostItem)
+        {
+            mConfig->update(hostItem);
+        }
+
+        void visitSipCryptoCertificateItem(const SipCryptoCertificateItemPtr& certificateItem)
+        {
+            mConfig->update(certificateItem);
+        }
+
+        void visitSipCryptoRequirementsItem(const SipCryptoRequirementsItemPtr& requirementsItem)
+        {
+            mConfig->update(requirementsItem);
+        }
+        
+        void visitSipCryptoItem(const ::AsteriskSCF::SIP::V1::SipCryptoItemPtr& cryptoItem)
+        {
+            mConfig->update(cryptoItem);
+        }
+        
+    private:
+        boost::shared_ptr<TLSTransportConfig> mConfig;
+    };
 public:
     /**
      * Constructor implementation for this
      */
-    TLSTransportImplPriv() : mTransportFactory(0) { pjsip_tls_setting_default(&mTLSSettings); };
+    TLSTransportConfig(const SipTLSTransportGroupPtr& group, PJSipManager* manager) :
+        mGroup(new SipTLSTransportGroup),
+        mManager(manager),
+        mTransportFactory(0),
+        mNeedsUpdating(false)
+    {
+        pjsip_tls_setting_default(&mTLSSettings);
+    };
 
     /**
      * Destructor implementation that shuts down the transport gracefully if we go away
      */
-    ~TLSTransportImplPriv()
+    ~TLSTransportConfig()
     {
         if (mTransportFactory)
         {
@@ -137,6 +543,99 @@ public:
         }
     };
 
+    SipConfigurationItemVisitorPtr getVisitor()
+    {
+        return new Visitor(boost::shared_ptr<TLSTransportConfig>(this));
+    }
+
+    void update(const SipHostItemPtr& hostItem)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        
+        mNeedsUpdating = (mAddress != hostItem->host || mPort != hostItem->port);
+        if (mNeedsUpdating)
+        {
+            mAddress = hostItem->host;
+            mPort = hostItem->port;
+        }
+    }
+
+    void update(const SipCryptoCertificateItemPtr& certificate)
+    {
+        //
+        // TODO: This is a little sketchy. We need to make sure that the certificateItem CAN NOT GO AWAY whilst
+        // mTLSSettings might get used. I'm referring to the fact that pj_str doesn't copy the string.
+        //
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mNeedsUpdating = true;
+        mTLSSettings.ca_list_file = pj_str((char*)certificate->certificateAuthority.c_str());
+        mTLSSettings.cert_file = pj_str((char*)certificate->certificate.c_str());
+        mTLSSettings.privkey_file = pj_str((char*)certificate->privateKey.c_str());
+        mTLSSettings.password = pj_str((char*)certificate->privateKeyPassword.c_str());
+    }
+
+    void update(const SipCryptoRequirementsItemPtr& requirements)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mNeedsUpdating = true;
+        mTLSSettings.verify_server = (requirements->requireVerifiedServer == false) ? PJ_FALSE : PJ_TRUE;
+        mTLSSettings.verify_client = (requirements->requireVerifiedClient == false) ? PJ_FALSE : PJ_TRUE;
+        mTLSSettings.require_client_cert = (requirements->requireClientCertificate == false) ? PJ_FALSE : PJ_TRUE;
+    }
+
+    void update(const SipCryptoItemPtr& crypto)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mNeedsUpdating = true;
+        if (crypto->protocolMethod == PROTOCOLMETHODUNSPECIFIED)
+        {
+            mTLSSettings.method = PJSIP_SSL_UNSPECIFIED_METHOD;
+        }
+        else if (crypto->protocolMethod == PROTOCOLMETHODTLSV1)
+        {
+            mTLSSettings.method = PJSIP_TLSV1_METHOD;
+        }
+        else if (crypto->protocolMethod == PROTOCOLMETHODSSLV2)
+        {
+            mTLSSettings.method = PJSIP_SSLV2_METHOD;
+        }
+        else if (crypto->protocolMethod == PROTOCOLMETHODSSLV3)
+        {
+            mTLSSettings.method = PJSIP_SSLV3_METHOD;
+        }
+        else if (crypto->protocolMethod == PROTOCOLMETHODSSLV23)
+        {
+           mTLSSettings.method = PJSIP_SSLV23_METHOD;
+        }
+        mTLSSettings.ciphers = pj_str((char*)crypto->supportedCiphers.c_str());
+        mTLSSettings.server_name = pj_str((char*)crypto->serverName.c_str());
+        mTLSSettings.timeout.sec = crypto->timeout;
+    }
+
+    void updated()
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        if (mNeedsUpdating)
+        {
+            mNeedsUpdating = false;
+            mTransportFactory = mManager->createTLSTransport(mAddress, mPort, &mTLSSettings);
+        }
+    }
+    
+    SipConfigurationGroupPtr getGroup() const
+    {
+        return mGroup;
+    }
+
+    SipTLSTransportGroupPtr getTypedGroup() const
+    {
+        return mGroup;
+    }
+
+private:
+
+    boost::shared_mutex mLock;
+    
     /**
      * Address itself.
      */
@@ -155,87 +654,511 @@ public:
     /**
      * Configuration group itself.
      */
-    SipTLSTransportGroupPtr mGroup;
+    mutable SipTLSTransportGroupPtr mGroup;
+
+    PJSipManager* mManager;
 
     /**
      * Transport factory within pjsip.
      */
     pjsip_tpfactory *mTransportFactory;
+
+    bool mNeedsUpdating;
 };
+typedef boost::shared_ptr<TLSTransportConfig> TLSTransportConfigPtr;
+typedef std::map<std::string, TLSTransportConfigPtr> TLSTransportMap;
+
+//
+// There are a lot of instances of looking up an item in collection and then doing something if it
+// is found. This reduces some of the boilerplate duplication.
+//
+template <typename C, typename I, typename K>
+bool getItem(const C& collection, I& iter, const K& key)
+{
+    iter = collection.find(key);
+    return iter != collection.end();
+}
+
+template <typename C, typename K>
+bool hasItem(const C& collection, const K& key)
+{
+    iter = collection.find(key);
+    return iter != collection.end();
+}
 
-class ConfigurationServiceImplPriv
+//
+// ConfigurationData goes into a class by itself to aide in sharing and
+// locking.
+//
+class ConfigurationData
 {
 public:
+
+    typedef std::map<std::string, SipDomainGroupPtr> DomainMap;
+    typedef std::map<std::string, SipEndpointGroupPtr> EndpointMap;
+    
+    ConfigurationData(PJSipManager* manager, 
+        const boost::shared_ptr<SipEndpointFactory>& factory,
+        const std::string& routingId, 
+        const LocatorRegistrySmartPrx& registry) : 
+        mGroup(new SipGeneralGroup),
+	mPJSipManager(manager), 
+        mEndpointFactory(factory), 
+        mRoutingId(routingId), 
+        mRoutingServiceLocatorRegistry(registry) 
+    {
+    }
+
     /**
-     * Constructor for this private class
+     * A simplified version for the general group.
      */
-    ConfigurationServiceImplPriv(PJSipManager *manager, boost::shared_ptr<SipEndpointFactory> factory, std::string& id,
-	AsteriskSCF::SmartProxy::SmartProxy<LocatorRegistryPrx> registry) :
-	mPJSipManager(manager), mEndpointFactory(factory), mRoutingId(id), mRoutingServiceLocatorRegistry(registry) { };
-    
+    void selectInto(const ConfigurationItemDict& requestedItems,
+            ConfigurationItemDict& returnedItems)
+    {
+        boost::shared_lock<boost::shared_mutex> lock(mLock);
+        selectIntoImpl(requestedItems, mGroup->configurationItems, returnedItems);
+    }
+
+    /**
+     * The generic version of selecting configuration items out of configuration groups.
+     **/
+    template <typename G>
+    bool selectIntoForGroup(const G& group, const G& newGroup)
+    {
+        boost::shared_lock<boost::shared_mutex> lock(mLock);
+        SipConfigurationGroupPtr g = getGroupFor(group);
+        if (g)
+        {
+            selectIntoImpl(group->configurationItems, g->configurationItems, newGroup->configurationItems);
+            return true;
+        }
+        return false;
+    }
+
+    template <typename G>
+    void removeFromGroup(const G& group)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        SipConfigurationGroupPtr g = getGroupFor(group);
+        if (g)
+        {
+            deleteFrom(group->configurationItems, g->configurationItems);
+        }
+    }
+
+    template <typename G>
+    SipConfigurationItemVisitorPtr update(const G& group)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        G v = getGroupFor(group);
+        if (!v)
+        {
+            v = createGroupTemplate(group);
+        }
+        performSerialCheck(group->configurationItems, v->configurationItems);
+        v->configurationItems.insert(group->configurationItems.begin(), group->configurationItems.end());
+        return updateGroup(v);
+    }
+
+    void remove(const SipGeneralGroupPtr&)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mGroup = 0;
+    }
+
+    void remove(const SipDomainGroupPtr& group)
+    {        
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mDomains.erase(mDomains.find(group->domain));
+    }
+
+    void remove(const SipEndpointGroupPtr& group)
+    {
+        boost::unique_lock<boost::shared_mutex> lock(mLock);
+        mEndpoints.erase(mEndpoints.find(group->name));
+    }
+
+    void remove(const SipUDPTransportGroupPtr& group)
+    {
+        //
+        // It's a good idea to hold a reference to this until after we release the lock
+        // on the config item. That way any code that might happen as a result of
+        // its destruction cannot come back and cause deadlocks on this object.
+        //
+        UDPTransportConfigPtr config;
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            UDPTransportMap::iterator i = mUDP.find(group->name);
+            if (i != mUDP.end())
+            {
+                config = i->second;
+                mUDP.erase(i);
+            }
+        }
+    }
+
+    void remove(const SipTCPTransportGroupPtr& group)
+    {
+        //
+        // It's a good idea to hold a reference to this until after we release the lock
+        // on the config item. That way any code that might happen as a result of
+        // its destruction cannot come back and cause deadlocks on this object.
+        //
+        TCPTransportConfigPtr config;
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            TCPTransportMap::iterator i = mTCP.find(group->name);
+            if (i != mTCP.end())
+            {
+                config = i->second;
+                mTCP.erase(i);
+            }
+        }
+    }
+
+    void remove(const SipTLSTransportGroupPtr& group)
+    {
+        //
+        // It's a good idea to hold a reference to this until after we release the lock
+        // on the config item. That way any code that might happen as a result of
+        // its destruction cannot come back and cause deadlocks on this object.
+        //
+        TLSTransportConfigPtr config;
+        {
+            boost::unique_lock<boost::shared_mutex> lock(mLock);
+            TLSTransportMap::iterator i = mTLS.find(group->name);
+            if (i != mTLS.end())
+            {
+                config = i->second;
+                mTLS.erase(i);
+            }
+        }
+    }
+
+    SipGeneralGroupPtr getGroupFor(const SipGeneralGroupPtr&)
+    {
+        return mGroup;
+    }
+
+    void copyGroupTemplates(ConfigurationGroupSeq& groups)
+    {
+        boost::shared_lock<boost::shared_mutex> lock(mLock);
+        groups.push_back(mGroup);
+        copyTransportTemplates(groups, mUDP);
+        copyTransportTemplates(groups, mTCP);
+        copyTransportTemplates(groups, mTLS);
+        copyTemplates(groups, mDomains);
+        copyTemplates(groups, mEndpoints);
+    }
+
+    //
+    // The following getItemsFor() members basically do a data member selection by type.
+    // Interestingly, this is simply an extension of the idea behind the visitor extension
+    // to Ice, but it takes it further, allowing a large degree of generalization in
+    // a shared data class.
+    //
+    const SipDomainGroupPtr getGroupFor(const SipDomainGroupPtr& group)
+    {
+        DomainMap::const_iterator i;
+        if (getItem(mDomains, i, group->domain))
+        {
+            return i->second;
+        }
+        return 0;
+    }
+
+    const SipEndpointGroupPtr getGroupFor(const SipEndpointGroupPtr& group)
+    {
+        EndpointMap::const_iterator i;
+        if (getItem(mEndpoints, i, group->name))
+        {
+            return i->second;
+        }
+        return 0;
+    }
+
+    const SipUDPTransportGroupPtr getGroupFor(const SipUDPTransportGroupPtr& group)
+    {
+        UDPTransportMap::const_iterator i;
+        if (getItem(mUDP, i, group->name))
+        {
+            return i->second->getTypedGroup();
+        }
+        return 0;
+    }
+
+    const SipTCPTransportGroupPtr getGroupFor(const SipTCPTransportGroupPtr& group)
+    {
+        TCPTransportMap::const_iterator i;
+        if (getItem(mTCP, i, group->name))
+        {
+            return i->second->getTypedGroup();
+        }
+        return 0;
+    }
+
+    const SipTLSTransportGroupPtr getGroupFor(const SipTLSTransportGroupPtr& group)
+    {
+        TLSTransportMap::const_iterator i;
+        if (getItem(mTLS, i, group->name))
+        {
+            return i->second->getTypedGroup();
+        }
+        return 0;
+    }
+
+private:
+
+    boost::shared_mutex mLock;
     /**
      * Configured SIP domains
      */
-    std::map<std::string, SipDomainGroupPtr> mConfiguredDomains;
+    DomainMap mDomains;
     
     /**
      * Configured UDP SIP transports
      */
-    std::map<std::string, boost::shared_ptr<UDPTransportImplPriv> > mConfiguredUDPTransports;
+    UDPTransportMap mUDP;
     
     /**
      * Configured TCP SIP transports
      */
-    std::map<std::string, boost::shared_ptr<TCPTransportImplPriv> > mConfiguredTCPTransports;
+    TCPTransportMap mTCP;
     
     /**
      * Configured TLS SIP transports
      */
-    std::map<std::string, boost::shared_ptr<TLSTransportImplPriv> > mConfiguredTLSTransports;
+    TLSTransportMap mTLS;
     
     /**
      * Configured SIP endpoints
      */
-    std::map<std::string, SipEndpointGroupPtr> mConfiguredEndpoints;
+    std::map<std::string, SipEndpointGroupPtr> mEndpoints;
     
     /**
      * General SIP configuration
      */
-    SipGeneralGroupPtr mGeneralGroup;
+    SipGeneralGroupPtr mGroup;
+
+    /**
+     * PJSipManager Pointer
+     */
+    PJSipManager* mPJSipManager;
+
+    /**
+     * Pointer to the endpoint factory used to create endpoints
+     */
+    boost::shared_ptr<SipEndpointFactory> mEndpointFactory;
+
+    /**
+     * Identifier for our endpoint locator.
+     */
+    std::string mRoutingId;
+
+    /**
+     * Proxy to endpoint locator registry
+     */
+    AsteriskSCF::SmartProxy::SmartProxy<LocatorRegistryPrx> mRoutingServiceLocatorRegistry;
+
+
+    //
+    // Helper function that does the selection out of one dictionary into another.
+    //
+    void selectIntoImpl(const ConfigurationItemDict& requestedItems,
+	    const ConfigurationItemDict& localItems,
+	    ConfigurationItemDict& returnedItems)
+    {
+        for (ConfigurationItemDict::const_iterator requestedItem = requestedItems.begin();
+             requestedItem != requestedItems.end();
+             ++requestedItem)
+        {
+            if (localItems.find(requestedItem->first) != localItems.end())
+            {
+                returnedItems.insert(*requestedItem);
+            }
+        }
+    }
+
+    void deleteFrom(const ConfigurationItemDict& itemsToDelete, ConfigurationItemDict& data)
+    {
+        for (ConfigurationItemDict::const_iterator i = itemsToDelete.begin();
+             i != itemsToDelete.end(); ++i)
+        {
+            data.erase(data.find(i->first));
+        }
+    }
+    
+    SipConfigurationItemVisitorPtr updateGroup(const SipGeneralGroupPtr&)
+    {
+        return 0;
+    }
+
+    SipConfigurationItemVisitorPtr updateGroup(const SipEndpointGroupPtr& group)
+    {
+        map<string, SipEndpointGroupPtr>::const_iterator i;
+        SipEndpointGroupPtr endpointGroup;
+        if (!getItem(mEndpoints, i, group->name))
+        {
+            endpointGroup = createGroupTemplate(group);
+            mEndpoints.insert(make_pair(group->name, endpointGroup));
+        }
+        else
+        {
+            endpointGroup = i->second;
+        }
+        SipEndpointPtr endpoint = mEndpointFactory->findByName(group->name);
+        if (!endpoint)
+        {
+            //
+            // XXX - something better to do than just ignore?
+            // Should never happen, and we can't do anything else without really messing things up.
+            //
+            return 0;
+        }
+        return boost::shared_ptr<EndpointConfigHelper>(
+            new EndpointConfigHelper(endpoint, mEndpointFactory, mRoutingServiceLocatorRegistry, mRoutingId))->getVisitor();
+    }
+
+    SipConfigurationItemVisitorPtr updateGroup(const SipDomainGroupPtr&)
+    {
+        return 0;
+    }
+    
+    SipConfigurationItemVisitorPtr updateGroup(const SipUDPTransportGroupPtr& group)
+    {
+        UDPTransportMap::const_iterator i;
+        UDPTransportConfigPtr transport;
+        if (!getItem(mUDP, i, group->name))
+        {
+            transport.reset(new UDPTransportConfig(group, mPJSipManager));
+            mUDP.insert(make_pair(group->name, transport));
+        }
+        else
+        {
+            transport = i->second;
+        }
+        return transport->getVisitor();
+    }
+
+    SipConfigurationItemVisitorPtr updateGroup(const SipTCPTransportGroupPtr& group)
+    {
+        TCPTransportMap::const_iterator i;
+        TCPTransportConfigPtr transport;
+        if (!getItem(mTCP, i, group->name))
+        {
+            transport.reset(new TCPTransportConfig(group, mPJSipManager));
+            mTCP.insert(make_pair(group->name, transport));
+        }
+        else
+        {
+            transport = i->second;
+        }
+        return transport->getVisitor();
+    }
+
+    SipConfigurationItemVisitorPtr updateGroup(const SipTLSTransportGroupPtr& group)
+    {
+        TLSTransportMap::const_iterator i;
+        TLSTransportConfigPtr transport;
+        if (!getItem(mTLS, i, group->name))
+        {
+            transport.reset(new TLSTransportConfig(group, mPJSipManager));
+            mTLS.insert(make_pair(group->name, transport));
+        }
+        else
+        {
+            transport = i->second;
+        }
+        return transport->getVisitor();
+    }
 
-    /**
-     * PJSipManager Pointer
-     */
-    PJSipManager *mPJSipManager;
+    template <class T>
+    void copyTemplates(ConfigurationGroupSeq& groups, const T& items)
+    {
+        typedef typename T::const_iterator TIter;
+        for (TIter g = items.begin(); g != items.end(); ++g)
+        {
+            groups.push_back(createGroupTemplate(g->second));
+        }
+    }
 
-    /**
-     * Pointer to the endpoint factory used to create endpoints
-     */
-    boost::shared_ptr<SipEndpointFactory> mEndpointFactory;
+    template <class T>
+    void copyTransportTemplates(ConfigurationGroupSeq& groups, const T& items)
+    {
+        typedef typename T::const_iterator TIter;
+        for (TIter g = items.begin(); g != items.end(); ++g)
+        {
+            groups.push_back(createGroupTemplate(g->second->getTypedGroup()));
+        }
+    }
+};
+typedef boost::shared_ptr<ConfigurationData> ConfigurationDataPtr;
 
-    /**
-     * Identifier for our endpoint locator.
-     */
-    std::string mRoutingId;
+/**
+ * Implementation of the configuration service.
+ */
+class ConfigurationServiceImpl : public AsteriskSCF::System::Configuration::V1::ConfigurationService
+{
+public:
+    ConfigurationServiceImpl(PJSipManager* manager, 
+        const boost::shared_ptr<SipEndpointFactory>& endpointFactory, 
+        const std::string& routingId,
+	const LocatorRegistrySmartPrx& locatorProxy);
+    ConfigurationGroupSeq getConfiguration(const ConfigurationGroupSeq&, const Ice::Current&);
+    ConfigurationGroupSeq getConfigurationAll(const ConfigurationGroupSeq&, const Ice::Current&);
+    ConfigurationGroupSeq getConfigurationGroups(const Ice::Current&);
+    void setConfiguration(const ConfigurationGroupSeq&, const Ice::Current&);
+    void removeConfigurationItems(const ConfigurationGroupSeq&, const Ice::Current&);
+    void removeConfigurationGroups(const ConfigurationGroupSeq&, const Ice::Current&);
+        
+    ConfigurationDataPtr getData()
+    {
+        return mData;
+    }
 
-    /**
-     * Proxy to endpoint locator registry
-     */
-    AsteriskSCF::SmartProxy::SmartProxy<LocatorRegistryPrx> mRoutingServiceLocatorRegistry;
+private:
+
+    //
+    // The configuration data should be kept separate from the servant. There
+    // are several practical reasons, but it comes down to the fact that the 
+    // data is shared and it's better to pass it around then the servant
+    // itself.
+    //
+    ConfigurationDataPtr mData;
 };
 
-ConfigurationServiceImpl::ConfigurationServiceImpl(PJSipManager *manager, boost::shared_ptr<SipEndpointFactory> factory,
-    std::string& id, AsteriskSCF::SmartProxy::SmartProxy<LocatorRegistryPrx> registry) :
-    mImplPriv(new ConfigurationServiceImplPriv(manager, factory, id, registry))
+typedef IceUtil::Handle<ConfigurationServiceImpl> ConfigurationServiceImplPtr;
+
+ConfigurationServiceImpl::ConfigurationServiceImpl(PJSipManager* manager, 
+    const boost::shared_ptr<SipEndpointFactory>& factory,
+    const std::string& routingId, 
+    const LocatorRegistrySmartPrx& registry) :
+    mData(new ConfigurationData(manager, factory, routingId, registry))
 {
 }
 
-ConfigurationGroupSeq ConfigurationServiceImpl::getConfiguration(const AsteriskSCF::System::Configuration::V1::ConfigurationGroupSeq& groups, const Ice::Current&)
+template <class T>
+static void getGeneric(const ConfigurationDataPtr& config, const T& group, ConfigurationGroupSeq& groups)
 {
-    class visitor : public SipConfigurationGroupVisitor
+    T newGroup(createGroupTemplate(group));
+    if (config->selectIntoForGroup(group, newGroup))
+    {
+        groups.push_back(newGroup);
+    }
+}
+
+ConfigurationGroupSeq ConfigurationServiceImpl::getConfiguration(
+    const AsteriskSCF::System::Configuration::V1::ConfigurationGroupSeq& groups, const Ice::Current&)
+{
+    class Visitor : public SipConfigurationGroupVisitor
     {
     public:
-	visitor(boost::shared_ptr<ConfigurationServiceImplPriv> implPriv, ConfigurationGroupSeq& visitorGroups) : mImplPriv(implPriv), mGroups(visitorGroups) { };
+	Visitor(const ConfigurationServiceImplPtr& impl, ConfigurationGroupSeq& visitorGroups) : 
+          mImpl(impl), 
+          mGroups(visitorGroups) 
+        { 
+            assert(mImpl);
+        };
 
     private:
 	/**
@@ -245,127 +1168,53 @@ ConfigurationGroupSeq ConfigurationServiceImpl::getConfiguration(const AsteriskS
 	    ConfigurationItemDict& localItems,
 	    ConfigurationItemDict& returnedItems)
 	{
-	    
 	    for (ConfigurationItemDict::iterator requestedItem = requestedItems.begin();
 		 requestedItem != requestedItems.end();
 		 ++requestedItem)
 	    {
-		ConfigurationItemDict::iterator localItem = localItems.find((*requestedItem).first);
-
-		if (localItem == localItems.end())
+		if (localItems.find(requestedItem->first) != localItems.end())
 		{
-		    continue;
+                    returnedItems.insert(*requestedItem);
 		}
-
-		returnedItems.insert(make_pair((*requestedItem).first, (*requestedItem).second));
 	    }
 	}
 
 	void visitSipGeneralGroup(const ::AsteriskSCF::SIP::V1::SipGeneralGroupPtr& group)
 	{
-	    if (!mImplPriv->mGeneralGroup)
-	    {
-		return;
-	    }
-
-	    SipGeneralGroupPtr returnedGroup = new SipGeneralGroup();
-
-	    insertRequestedConfigurationItems(group->configurationItems, mImplPriv->mGeneralGroup->configurationItems, returnedGroup->configurationItems);
-
-	    mGroups.push_back(returnedGroup);
+            getGeneric<SipGeneralGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 
 	void visitSipDomainGroup(const ::AsteriskSCF::SIP::V1::SipDomainGroupPtr& group)
 	{
-	    std::map<std::string, SipDomainGroupPtr>::iterator localDomain = mImplPriv->mConfiguredDomains.find(group->domain);
-
-	    if (localDomain == mImplPriv->mConfiguredDomains.end())
-	    {
-		return;
-	    }
-
-	    SipDomainGroupPtr returnedGroup = new SipDomainGroup();
-	    returnedGroup->domain = group->domain;
-
-	    insertRequestedConfigurationItems(group->configurationItems, (*localDomain).second->configurationItems, returnedGroup->configurationItems);
-
-	    mGroups.push_back(returnedGroup);
+            getGeneric<SipDomainGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 
 	void visitSipUDPTransportGroup(const ::AsteriskSCF::SIP::V1::SipUDPTransportGroupPtr& group)
 	{
-	    std::map<std::string, boost::shared_ptr<UDPTransportImplPriv> >::iterator localTransport = mImplPriv->mConfiguredUDPTransports.find(group->name);
-	    
-	    if (localTransport == mImplPriv->mConfiguredUDPTransports.end())
-	    {
-		return;
-	    }
-	    
-	    SipUDPTransportGroupPtr returnedGroup = new SipUDPTransportGroup();
-	    returnedGroup->name = group->name;
-	    
-	    insertRequestedConfigurationItems(group->configurationItems, (*localTransport).second->mGroup->configurationItems, returnedGroup->configurationItems);
-	    
-	    mGroups.push_back(returnedGroup);
+            getGeneric<SipUDPTransportGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 	
 	void visitSipTCPTransportGroup(const ::AsteriskSCF::SIP::V1::SipTCPTransportGroupPtr& group)
 	{
-	    std::map<std::string,  boost::shared_ptr<TCPTransportImplPriv> >::iterator localTransport = mImplPriv->mConfiguredTCPTransports.find(group->name);
-	    
-	    if (localTransport == mImplPriv->mConfiguredTCPTransports.end())
-	    {
-		return;
-	    }
-	    
-	    SipTCPTransportGroupPtr returnedGroup = new SipTCPTransportGroup();
-	    returnedGroup->name = group->name;
-	    
-	    insertRequestedConfigurationItems(group->configurationItems, (*localTransport).second->mGroup->configurationItems, returnedGroup->configurationItems);
-	    
-	    mGroups.push_back(returnedGroup);
+            getGeneric<SipTCPTransportGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 	
 	void visitSipTLSTransportGroup(const ::AsteriskSCF::SIP::V1::SipTLSTransportGroupPtr& group)
 	{
-	    std::map<std::string, boost::shared_ptr<TLSTransportImplPriv> >::iterator localTransport = mImplPriv->mConfiguredTLSTransports.find(group->name);
-	    
-	    if (localTransport == mImplPriv->mConfiguredTLSTransports.end())
-	    {
-		return;
-	    }
-	    
-	    SipTLSTransportGroupPtr returnedGroup = new SipTLSTransportGroup();
-	    returnedGroup->name = group->name;
-	    
-	    insertRequestedConfigurationItems(group->configurationItems, (*localTransport).second->mGroup->configurationItems, returnedGroup->configurationItems);
-	    
-	    mGroups.push_back(returnedGroup);
+            getGeneric<SipTLSTransportGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 	
 	void visitSipEndpointGroup(const ::AsteriskSCF::SIP::V1::SipEndpointGroupPtr& group)
 	{
-	    std::map<std::string, SipEndpointGroupPtr>::iterator localEndpoint = mImplPriv->mConfiguredEndpoints.find(group->name);
-	    
-	    if (localEndpoint == mImplPriv->mConfiguredEndpoints.end())
-	    {
-		return;
-	    }
-	    
-	    SipEndpointGroupPtr returnedGroup = new SipEndpointGroup();
-	    returnedGroup->name = group->name;
-	    
-	    insertRequestedConfigurationItems(group->configurationItems, (*localEndpoint).second->configurationItems, returnedGroup->configurationItems);
-	    
-	    mGroups.push_back(returnedGroup);
+            getGeneric<SipEndpointGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 
-	boost::shared_ptr<ConfigurationServiceImplPriv> mImplPriv;
+	ConfigurationServiceImplPtr mImpl;
 	ConfigurationGroupSeq& mGroups;
     };
     
     ConfigurationGroupSeq newGroups;
-    SipConfigurationGroupVisitorPtr v = new visitor(mImplPriv, newGroups);
+    SipConfigurationGroupVisitorPtr v = new Visitor(this, newGroups);
     
     for (ConfigurationGroupSeq::const_iterator group = groups.begin(); group != groups.end(); ++group)
     {
@@ -375,91 +1224,65 @@ ConfigurationGroupSeq ConfigurationServiceImpl::getConfiguration(const AsteriskS
     return newGroups;
 }
 
-ConfigurationGroupSeq ConfigurationServiceImpl::getConfigurationAll(const AsteriskSCF::System::Configuration::V1::ConfigurationGroupSeq& groups, const Ice::Current&)
+template <class T>
+static void genericGetAll(const ConfigurationDataPtr& config, const T& group, ConfigurationGroupSeq& groups)
+{
+    SipConfigurationGroupPtr g = config->getGroupFor(group);
+    if (g)
+    {
+        groups.push_back(g);
+    }
+}
+
+ConfigurationGroupSeq ConfigurationServiceImpl::getConfigurationAll(const AsteriskSCF::System::Configuration::V1::ConfigurationGroupSeq& groups,
+        const Ice::Current&)
 {
-    class visitor : public SipConfigurationGroupVisitor
+    class Visitor : public SipConfigurationGroupVisitor
     {
     public:
-	visitor(boost::shared_ptr<ConfigurationServiceImplPriv> implPriv, ConfigurationGroupSeq& visitorGroups) :
-	    mImplPriv(implPriv), mGroups(visitorGroups) { };
+	Visitor(const ConfigurationServiceImplPtr& impl, ConfigurationGroupSeq& visitorGroups) :
+	    mImpl(impl), 
+            mGroups(visitorGroups) 
+        { 
+        };
 	
     private:
-	void visitSipGeneralGroup(const ::AsteriskSCF::SIP::V1::SipGeneralGroupPtr&)
+	void visitSipGeneralGroup(const ::AsteriskSCF::SIP::V1::SipGeneralGroupPtr& group)
 	{
-	    if (!mImplPriv->mGeneralGroup)
-	    {
-		return;
-	    }
-	    
-	    mGroups.push_back(mImplPriv->mGeneralGroup);
-	};
-	
+            genericGetAll<SipGeneralGroupPtr>(mImpl->getData(), group, mGroups);
+        }
+
 	void visitSipDomainGroup(const ::AsteriskSCF::SIP::V1::SipDomainGroupPtr& group)
 	{
-	    std::map<std::string, SipDomainGroupPtr>::iterator localDomain = mImplPriv->mConfiguredDomains.find(group->domain);
-	    
-	    if (localDomain == mImplPriv->mConfiguredDomains.end())
-	    {
-		return;
-	    }
-	    
-	    mGroups.push_back((*localDomain).second);
+            genericGetAll<SipDomainGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 	
 	void visitSipUDPTransportGroup(const ::AsteriskSCF::SIP::V1::SipUDPTransportGroupPtr& group)
 	{
-	    std::map<std::string, boost::shared_ptr<UDPTransportImplPriv> >::iterator localTransport = mImplPriv->mConfiguredUDPTransports.find(group->name);
-	    
-	    if (localTransport == mImplPriv->mConfiguredUDPTransports.end())
-	    {
-		return;
-	    }
-	    
-	    mGroups.push_back((*localTransport).second->mGroup);
+            genericGetAll<SipUDPTransportGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 	
 	void visitSipTCPTransportGroup(const ::AsteriskSCF::SIP::V1::SipTCPTransportGroupPtr& group)
 	{
-	    std::map<std::string,  boost::shared_ptr<TCPTransportImplPriv> >::iterator localTransport = mImplPriv->mConfiguredTCPTransports.find(group->name);
-	    
-	    if (localTransport == mImplPriv->mConfiguredTCPTransports.end())
-	    {
-		return;
-	    }
-	    
-	    mGroups.push_back((*localTransport).second->mGroup);
+            genericGetAll<SipTCPTransportGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 	
 	void visitSipTLSTransportGroup(const ::AsteriskSCF::SIP::V1::SipTLSTransportGroupPtr& group)
 	{
-	    std::map<std::string, boost::shared_ptr<TLSTransportImplPriv> >::iterator localTransport = mImplPriv->mConfiguredTLSTransports.find(group->name);
-	    
-	    if (localTransport == mImplPriv->mConfiguredTLSTransports.end())
-	    {
-		return;
-	    }
-	    
-	    mGroups.push_back((*localTransport).second->mGroup);
+            genericGetAll<SipTLSTransportGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 	
 	void visitSipEndpointGroup(const ::AsteriskSCF::SIP::V1::SipEndpointGroupPtr& group)
 	{
-	    std::map<std::string, SipEndpointGroupPtr>::iterator localEndpoint = mImplPriv->mConfiguredEndpoints.find(group->name);
-	    
-	    if (localEndpoint == mImplPriv->mConfiguredEndpoints.end())
-	    {
-		return;
-	    }
-	    
-	    mGroups.push_back((*localEndpoint).second);
+            genericGetAll<SipEndpointGroupPtr>(mImpl->getData(), group, mGroups);
 	};
 
-	boost::shared_ptr<ConfigurationServiceImplPriv> mImplPriv;
+	ConfigurationServiceImplPtr mImpl;
 	ConfigurationGroupSeq& mGroups;
     };
     
     ConfigurationGroupSeq newGroups;
-    SipConfigurationGroupVisitorPtr v = new visitor(mImplPriv, newGroups);
+    SipConfigurationGroupVisitorPtr v = new Visitor(this, newGroups);
     
     for (ConfigurationGroupSeq::const_iterator group = groups.begin(); group != groups.end(); ++group)
     {
@@ -472,609 +1295,124 @@ ConfigurationGroupSeq ConfigurationServiceImpl::getConfigurationAll(const Asteri
 ConfigurationGroupSeq ConfigurationServiceImpl::getConfigurationGroups(const Ice::Current&)
 {
     ConfigurationGroupSeq groups;
-    
-    if (mImplPriv->mGeneralGroup)
-    {
-	SipGeneralGroupPtr general = new SipGeneralGroup();
-	groups.push_back(general);
-    }
-    
-    for (std::map<std::string, SipDomainGroupPtr>::iterator group = mImplPriv->mConfiguredDomains.begin();
-	 group != mImplPriv->mConfiguredDomains.end();
-	 ++group)
-    {
-	SipDomainGroupPtr domain = new SipDomainGroup();
-	domain->domain = group->second->domain;
-	groups.push_back(domain);
-    }
+    mData->copyGroupTemplates(groups);
+    return groups;
+}
 
-    for (std::map<std::string, boost::shared_ptr<UDPTransportImplPriv> >::iterator group = mImplPriv->mConfiguredUDPTransports.begin();
-	 group != mImplPriv->mConfiguredUDPTransports.end();
-	 ++group)
-    {
-	SipUDPTransportGroupPtr transport = new SipUDPTransportGroup();
-	transport->name = group->second->mGroup->name;
-	groups.push_back(transport);
-    }
-    
-    for (std::map<std::string,  boost::shared_ptr<TCPTransportImplPriv> >::iterator group = mImplPriv->mConfiguredTCPTransports.begin();
-	 group != mImplPriv->mConfiguredTCPTransports.end();
-	 ++group)
-    {
-	SipTCPTransportGroupPtr transport = new SipTCPTransportGroup();
-	transport->name = group->second->mGroup->name;
-	groups.push_back(transport);
-    }
-    
-    for (std::map<std::string, boost::shared_ptr<TLSTransportImplPriv> >::iterator group = mImplPriv->mConfiguredTLSTransports.begin();
-	 group != mImplPriv->mConfiguredTLSTransports.end();
-	 ++group)
-    {
-	SipTLSTransportGroupPtr transport = new SipTLSTransportGroup();
-	transport->name = group->second->mGroup->name;
-	groups.push_back(transport);
-    }
-    
-    for (std::map<std::string, SipEndpointGroupPtr>::iterator group = mImplPriv->mConfiguredEndpoints.begin();
-	 group != mImplPriv->mConfiguredEndpoints.end();
-	 ++group)
+template <class T>
+static void genericSet(const ConfigurationDataPtr& config, const T& group)
+{
+    SipConfigurationItemVisitorPtr visitor = config->update(group);
+
+    if (visitor)
     {
-	SipEndpointGroupPtr endpoint = new SipEndpointGroup();
-	endpoint->name = group->second->name;
-	groups.push_back(endpoint);
+        for (ConfigurationItemDict::const_iterator item = group->configurationItems.begin();
+                item != group->configurationItems.end();
+                ++item)
+        {
+            item->second->visit(visitor);
+        }
     }
-    
-    return groups;
 }
 
 void ConfigurationServiceImpl::setConfiguration(const AsteriskSCF::System::Configuration::V1::ConfigurationGroupSeq& groups, const Ice::Current&)
 {
-    class groupsVisitor : public SipConfigurationGroupVisitor
+    class GroupsVisitor : public SipConfigurationGroupVisitor
     {
     public:
-	groupsVisitor(boost::shared_ptr<ConfigurationServiceImplPriv> implPriv) : mImplPriv(implPriv) { };
+	GroupsVisitor(const ConfigurationServiceImplPtr& impl) : 
+          mImpl(impl) 
+        { 
+        };
 	
     private:
-	/**
-	 * Helper function which performs serial number checking of items
-	 */
-	void performSerialCheck(ConfigurationItemDict& changedItems, ConfigurationItemDict& localItems)
-	{
-	    for (ConfigurationItemDict::iterator item = changedItems.begin();
-		 item != changedItems.end();
-		 ++item)
-	    {
-		// If serial checking is to be skipped for this item just skip over it
-		if ((*item).second->serialNumber == -1)
-		{
-		    continue;
-		}
-		
-		ConfigurationItemDict::iterator localItem = localItems.find((*item).first);
-		
-		if (localItem == localItems.end())
-		{
-		    // This is a new item so serial checking does not apply
-		    continue;
-		}
-		
-		if ((*item).second->serialNumber < (*localItem).second->serialNumber)
-		{
-		    /* XXX Need to throw the exception */
-		}
-	    }
-	}
-	
+        
 	void visitSipGeneralGroup(const ::AsteriskSCF::SIP::V1::SipGeneralGroupPtr& group)
 	{
-	    if (!mImplPriv->mGeneralGroup)
-	    {
-		mImplPriv->mGeneralGroup = new SipGeneralGroup();
-	    }
-	    else
-	    {
-		performSerialCheck(group->configurationItems, mImplPriv->mGeneralGroup->configurationItems);
-	    }
-	    
-	    class generalItemsVisitor : public SipConfigurationItemVisitor
-	    {
-	    public:
-	    private:
-	    };
-	    
-	    SipConfigurationItemVisitorPtr generalVisitor = new generalItemsVisitor();
-	    
-	    for (ConfigurationItemDict::const_iterator item = group->configurationItems.begin();
-		 item != group->configurationItems.end();
-		 ++item)
-	    {
-		mImplPriv->mGeneralGroup->configurationItems.insert(make_pair((*item).first, (*item).second));
-		(*item).second->visit(generalVisitor);
-	    }
+            genericSet<SipGeneralGroupPtr>(mImpl->getData(), group);
 	}
 	
 	void visitSipDomainGroup(const ::AsteriskSCF::SIP::V1::SipDomainGroupPtr& group)
 	{
-	    std::map<std::string, SipDomainGroupPtr>::iterator localDomainGroup = mImplPriv->mConfiguredDomains.find(group->domain);
-	    SipDomainGroupPtr localDomain;
-	    
-	    if (localDomainGroup == mImplPriv->mConfiguredDomains.end())
-	    {
-		localDomain = new SipDomainGroup;
-		localDomain->domain = group->domain;
-		mImplPriv->mConfiguredDomains.insert(make_pair(group->domain, localDomain));
-	    }
-	    else
-	    {
-		localDomain = (*localDomainGroup).second;
-		performSerialCheck(group->configurationItems, localDomain->configurationItems);
-	    }
-	    
-	    class domainItemsVisitor : public SipConfigurationItemVisitor
-	    {
-	    public:
-	    private:
-	    };
-	    
-	    SipConfigurationItemVisitorPtr domainVisitor = new domainItemsVisitor();
-	    
-	    for (ConfigurationItemDict::const_iterator item = group->configurationItems.begin();
-		 item != group->configurationItems.end();
-		 ++item)
-	    {
-		localDomain->configurationItems.insert(make_pair((*item).first, (*item).second));
-		(*item).second->visit(domainVisitor);
-	    }
+            genericSet<SipDomainGroupPtr>(mImpl->getData(), group);
 	};
 	
 	void visitSipUDPTransportGroup(const ::AsteriskSCF::SIP::V1::SipUDPTransportGroupPtr& group)
 	{
-	    std::map<std::string, boost::shared_ptr<UDPTransportImplPriv> >::iterator localTransportGroup = mImplPriv->mConfiguredUDPTransports.find(group->name);
-	    boost::shared_ptr<UDPTransportImplPriv> localTransport;
-	    
-	    if (localTransportGroup == mImplPriv->mConfiguredUDPTransports.end())
-	    {
-		boost::shared_ptr<UDPTransportImplPriv> newTransport(new UDPTransportImplPriv());
-		localTransport = newTransport;
-		localTransport->mGroup = new SipUDPTransportGroup;
-		localTransport->mGroup->name = group->name;
-		mImplPriv->mConfiguredUDPTransports.insert(make_pair(group->name, localTransport));
-	    }
-	    else
-	    {
-		localTransport = (*localTransportGroup).second;
-		performSerialCheck(group->configurationItems, localTransport->mGroup->configurationItems);
-	    }
-	    
-	    class udpTransportItemsVisitor : public SipConfigurationItemVisitor
-	    {
-	    public:
-		udpTransportItemsVisitor(boost::shared_ptr<UDPTransportImplPriv> udpLocalTransport) : mLocalTransport(udpLocalTransport) { };
-		
-		void visitSipHostItem(const ::AsteriskSCF::SIP::V1::SipHostItemPtr& hostItem)
-		{
-		    mLocalTransport->mAddress = hostItem->host;
-		    mLocalTransport->mPort = hostItem->port;
-		};
-	    private:
-		boost::shared_ptr<UDPTransportImplPriv> mLocalTransport;
-	    };
-	    
-	    std::string oldAddress = localTransport->mAddress;
-	    int oldPort = localTransport->mPort;
-	    
-	    SipConfigurationItemVisitorPtr udpTransportVisitor = new udpTransportItemsVisitor(localTransport);
-	    
-	    for (ConfigurationItemDict::const_iterator item = group->configurationItems.begin();
-		 item != group->configurationItems.end();
-		 ++item)
-	    {
-		localTransport->mGroup->configurationItems.insert(make_pair((*item).first, (*item).second));
-		(*item).second->visit(udpTransportVisitor);
-	    }
-	    
-	    // Reconcile all the changes received
-	    if (oldAddress != localTransport->mAddress || oldPort != localTransport->mPort)
-	    {
-		if (localTransport->mTransport)
-		{
-		    pjsip_transport_shutdown(localTransport->mTransport);
-		}
-		
-		localTransport->mTransport = mImplPriv->mPJSipManager->createUDPTransport(localTransport->mAddress, localTransport->mPort);
-	    }
+            genericSet<SipUDPTransportGroupPtr>(mImpl->getData(), group);
 	};
 	
 	void visitSipTCPTransportGroup(const ::AsteriskSCF::SIP::V1::SipTCPTransportGroupPtr& group)
 	{
-	    std::map<std::string,  boost::shared_ptr<TCPTransportImplPriv> >::iterator localTransportGroup = mImplPriv->mConfiguredTCPTransports.find(group->name);
-	    boost::shared_ptr<TCPTransportImplPriv> localTransport;
-	    
-	    if (localTransportGroup == mImplPriv->mConfiguredTCPTransports.end())
-	    {
-		boost::shared_ptr<TCPTransportImplPriv> newTransport(new TCPTransportImplPriv());
-                localTransport = newTransport;
-                localTransport->mGroup = new SipTCPTransportGroup;
-                localTransport->mGroup->name = group->name;
-		mImplPriv->mConfiguredTCPTransports.insert(make_pair(group->name, localTransport));
-	    }
-	    else
-	    {
-		localTransport = (*localTransportGroup).second;
-		performSerialCheck(group->configurationItems, localTransport->mGroup->configurationItems);
-	    }
-	    
-            class tcpTransportItemsVisitor : public SipConfigurationItemVisitor
-            {
-            public:
-                tcpTransportItemsVisitor(boost::shared_ptr<TCPTransportImplPriv> tcpLocalTransport) : mLocalTransport(tcpLocalTransport) { };
-
-                void visitSipHostItem(const ::AsteriskSCF::SIP::V1::SipHostItemPtr& hostItem)
-                {
-                    mLocalTransport->mAddress = hostItem->host;
-                    mLocalTransport->mPort = hostItem->port;
-                };
-            private:
-		boost::shared_ptr<TCPTransportImplPriv> mLocalTransport;
-            };
-
-	    std::string oldAddress = localTransport->mAddress;
-            int oldPort = localTransport->mPort;
-
-            SipConfigurationItemVisitorPtr tcpTransportVisitor = new tcpTransportItemsVisitor(localTransport);
-
-            for (ConfigurationItemDict::const_iterator item = group->configurationItems.begin();
-                 item != group->configurationItems.end();
-                 ++item)
-            {
-                localTransport->mGroup->configurationItems.insert(make_pair((*item).first, (*item).second));
-                (*item).second->visit(tcpTransportVisitor);
-            }
-
-            // Reconcile all the changes received
-            if (oldAddress != localTransport->mAddress || oldPort != localTransport->mPort)
-            {
-                if (localTransport->mTransportFactory)
-                {
-		    // I hope eventually it becomes possible to do this... but for now it is not
-                }
-
-                localTransport->mTransportFactory = mImplPriv->mPJSipManager->createTCPTransport(localTransport->mAddress, localTransport->mPort);
-            }
+            genericSet<SipTCPTransportGroupPtr>(mImpl->getData(), group);
 	};
 	
 	void visitSipTLSTransportGroup(const ::AsteriskSCF::SIP::V1::SipTLSTransportGroupPtr& group)
 	{
-	    std::map<std::string,  boost::shared_ptr<TLSTransportImplPriv> >::iterator localTransportGroup = mImplPriv->mConfiguredTLSTransports.find(group->name);
-            boost::shared_ptr<TLSTransportImplPriv> localTransport;
-
-	    if (localTransportGroup == mImplPriv->mConfiguredTLSTransports.end())
-	    {
-		boost::shared_ptr<TLSTransportImplPriv> newTransport(new TLSTransportImplPriv());
-		localTransport = newTransport;
-		localTransport->mGroup = new SipTLSTransportGroup;
-		localTransport->mGroup->name = group->name;
-		mImplPriv->mConfiguredTLSTransports.insert(make_pair(group->name, localTransport));
-	    }
-	    else
-	    {
-		localTransport = (*localTransportGroup).second;
-		performSerialCheck(group->configurationItems, localTransport->mGroup->configurationItems);
-	    }
-
-	    class tlsTransportItemsVisitor : public SipConfigurationItemVisitor
-	    {
-	    public:
-		tlsTransportItemsVisitor(boost::shared_ptr<TLSTransportImplPriv> tlsLocalTransport) : mLocalTransport(tlsLocalTransport) { };
-
-		void visitSipHostItem(const ::AsteriskSCF::SIP::V1::SipHostItemPtr& hostItem)
-		{
-		    mLocalTransport->mAddress = hostItem->host;
-		    mLocalTransport->mPort = hostItem->port;
-		};
-
-		void visitSipCryptoCertificateItem(const ::AsteriskSCF::SIP::V1::SipCryptoCertificateItemPtr& certificateItem)
-		{
-		    mLocalTransport->mTLSSettings.ca_list_file = pj_str((char*)certificateItem->certificateAuthority.c_str());
-		    mLocalTransport->mTLSSettings.cert_file = pj_str((char*)certificateItem->certificate.c_str());
-		    mLocalTransport->mTLSSettings.privkey_file = pj_str((char*)certificateItem->privateKey.c_str());
-		    mLocalTransport->mTLSSettings.password = pj_str((char*)certificateItem->privateKeyPassword.c_str());
-		};
-
-		void visitSipCryptoRequirementsItem(const ::AsteriskSCF::SIP::V1::SipCryptoRequirementsItemPtr& requirementsItem)
-		{
-		    mLocalTransport->mTLSSettings.verify_server = (requirementsItem->requireVerifiedServer == false) ? PJ_FALSE : PJ_TRUE;
-		    mLocalTransport->mTLSSettings.verify_client = (requirementsItem->requireVerifiedClient == false) ? PJ_FALSE : PJ_TRUE;
-		    mLocalTransport->mTLSSettings.require_client_cert = (requirementsItem->requireClientCertificate == false) ? PJ_FALSE : PJ_TRUE;
-		};
-
-		void visitSipCryptoItem(const ::AsteriskSCF::SIP::V1::SipCryptoItemPtr& cryptoItem)
-		{
-		    if (cryptoItem->protocolMethod == PROTOCOLMETHODUNSPECIFIED)
-		    {
-			mLocalTransport->mTLSSettings.method = PJSIP_SSL_UNSPECIFIED_METHOD;
-		    }
-		    else if (cryptoItem->protocolMethod == PROTOCOLMETHODTLSV1)
-		    {
-			mLocalTransport->mTLSSettings.method = PJSIP_TLSV1_METHOD;
-		    }
-		    else if (cryptoItem->protocolMethod == PROTOCOLMETHODSSLV2)
-		    {
-			mLocalTransport->mTLSSettings.method = PJSIP_SSLV2_METHOD;
-		    }
-		    else if (cryptoItem->protocolMethod == PROTOCOLMETHODSSLV3)
-		    {
-			mLocalTransport->mTLSSettings.method = PJSIP_SSLV3_METHOD;
-		    }
-		    else if (cryptoItem->protocolMethod == PROTOCOLMETHODSSLV23)
-		    {
-			mLocalTransport->mTLSSettings.method = PJSIP_SSLV23_METHOD;
-		    }
-		    mLocalTransport->mTLSSettings.ciphers = pj_str((char*)cryptoItem->supportedCiphers.c_str());
-		    mLocalTransport->mTLSSettings.server_name = pj_str((char*)cryptoItem->serverName.c_str());
-		    mLocalTransport->mTLSSettings.timeout.sec = cryptoItem->timeout;
-		};
-	    private:
-		boost::shared_ptr<TLSTransportImplPriv> mLocalTransport;
-	    };
-
-	    std::string oldAddress = localTransport->mAddress;
-	    int oldPort = localTransport->mPort;
-
-	    SipConfigurationItemVisitorPtr tlsTransportVisitor = new tlsTransportItemsVisitor(localTransport);
-
-	    for (ConfigurationItemDict::const_iterator item = group->configurationItems.begin();
-		 item != group->configurationItems.end();
-		 ++item)
-	    {
-		localTransport->mGroup->configurationItems.insert(make_pair((*item).first, (*item).second));
-		(*item).second->visit(tlsTransportVisitor);
-	    }
-
-	    // Reconcile all the changes received
-	    if (oldAddress != localTransport->mAddress || oldPort != localTransport->mPort)
-	    {
-		if (localTransport->mTransportFactory)
-		{
-		    // I hope eventually it becomes possible to do this... but for now it is not
-		}
-
-		std::cout << "Address: " << localTransport->mAddress << std::endl;
-		localTransport->mTransportFactory = mImplPriv->mPJSipManager->createTLSTransport(localTransport->mAddress, localTransport->mPort, &localTransport->mTLSSettings);
-	    }
+            genericSet<SipTLSTransportGroupPtr>(mImpl->getData(), group);
 	};
 
         void visitSipEndpointGroup(const ::AsteriskSCF::SIP::V1::SipEndpointGroupPtr& group)
         {
-	    std::map<std::string, SipEndpointGroupPtr>::iterator localEndpointGroup = mImplPriv->mConfiguredEndpoints.find(group->name);
-            SipEndpointGroupPtr localEndpoint;
-	    SipEndpointPtr endpoint = 0;
-
-            if (localEndpointGroup == mImplPriv->mConfiguredEndpoints.end())
-            {
-                localEndpoint = new SipEndpointGroup();
-                localEndpoint->name = group->name;
-                mImplPriv->mConfiguredEndpoints.insert(make_pair(group->name, localEndpoint));
-		endpoint = mImplPriv->mEndpointFactory->createEndpoint(group->name);
-            }
-            else
-            {
-                localEndpoint = (*localEndpointGroup).second;
-                performSerialCheck(group->configurationItems, localEndpoint->configurationItems);
-		endpoint = mImplPriv->mEndpointFactory->findByName(group->name);
-            }
-
-	    if (endpoint == 0)
-	    {
-                // This should never happen... if it does then the configuration system and the endpoint factory are out of sync somehow O.o
-		return;
-	    }
-
-            class endpointItemsVisitor : public SipConfigurationItemVisitor
-            {
-            public:
-		endpointItemsVisitor(SipEndpointPtr& visitedEndpoint) : mEndpoint(visitedEndpoint) { };
-
-		void visitSipAllowableCallDirectionItem(const ::AsteriskSCF::SIP::V1::SipAllowableCallDirectionItemPtr& direction)
-		{
-		    enum Direction callDirection;
-
-		    if (direction->callDirection == Inbound)
-		    {
-			callDirection = INBOUND;
-		    }
-		    else if (direction->callDirection == Outbound)
-		    {
-			callDirection = OUTBOUND;
-		    }
-		    else if (direction->callDirection == Both)
-		    {
-			callDirection = BOTH;
-		    }
-		    else
-		    {
-			callDirection = NONE;
-		    }
-		    mEndpoint->setCallDirection(callDirection);
-		};
-
-		void visitSipSourceTransportAddressItem(const ::AsteriskSCF::SIP::V1::SipSourceTransportAddressItemPtr& source)
-		{
-		    mEndpoint->setSourceAddress(source->host, source->port);
-		};
-
-		void visitSipTargetDestinationAddressItem(const ::AsteriskSCF::SIP::V1::SipTargetDestinationAddressItemPtr& target)
-		{
-		    mEndpoint->setTargetAddress(target->host, target->port);
-		};
-            private:
-		SipEndpointPtr& mEndpoint;
-            };
-
-            SipConfigurationItemVisitorPtr endpointVisitor = new endpointItemsVisitor(endpoint);
-
-            for (ConfigurationItemDict::const_iterator item = group->configurationItems.begin();
-                 item != group->configurationItems.end();
-                 ++item)
-            {
-                localEndpoint->configurationItems.insert(make_pair((*item).first, (*item).second));
-                (*item).second->visit(endpointVisitor);
-            }
+            genericSet<SipEndpointGroupPtr>(mImpl->getData(), group);
         };
 	
-	boost::shared_ptr<ConfigurationServiceImplPriv> mImplPriv;
+	ConfigurationServiceImplPtr mImpl;
     };
     
-    SipConfigurationGroupVisitorPtr v = new groupsVisitor(mImplPriv);
+    SipConfigurationGroupVisitorPtr v = new GroupsVisitor(this);
     
     for (ConfigurationGroupSeq::const_iterator group = groups.begin(); group != groups.end(); ++group)
     {
 	(*group)->visit(v);
     }
-
-    // Update endpoint locator with any new destinations that may have been pushed
-    RegExSeq destinations;
-    mImplPriv->mEndpointFactory->generateRoutingDestinations(destinations);
-    mImplPriv->mRoutingServiceLocatorRegistry->setEndpointLocatorDestinationIds(mImplPriv->mRoutingId, destinations);
 }
 
-void ConfigurationServiceImpl::removeConfigurationItems(const AsteriskSCF::System::Configuration::V1::ConfigurationGroupSeq& groups, const Ice::Current&)
+void ConfigurationServiceImpl::removeConfigurationItems(const AsteriskSCF::System::Configuration::V1::ConfigurationGroupSeq& groups,
+        const Ice::Current&)
 {
-    class groupsVisitor : public SipConfigurationGroupVisitor
+    class GroupsVisitor : public SipConfigurationGroupVisitor
     {
     public:
-	groupsVisitor(boost::shared_ptr<ConfigurationServiceImplPriv> implPriv) : mImplPriv(implPriv) { };
-	
-	void removeItems(SipConfigurationItemVisitor* visitor, ConfigurationItemDict& itemsToRemove,
-	    ConfigurationItemDict& localItems)
-	{
-	    for (ConfigurationItemDict::const_iterator item = itemsToRemove.begin();
-		 item != itemsToRemove.end();
-		 ++item)
-	    {
-		ConfigurationItemDict::iterator localItem = localItems.find((*item).first);
-		if (localItem ==  localItems.end())
-		{
-		    continue;
-		}
-		if (visitor != 0)
-		{
-		    (*item).second->visit(visitor);
-		}
-		localItems.erase(localItem);
-	    }
-	}
+	GroupsVisitor(const ConfigurationServiceImplPtr& impl) : 
+          mImpl(impl) 
+        { 
+        };
 	
 	void visitSipGeneralGroup(const ::AsteriskSCF::SIP::V1::SipGeneralGroupPtr& group)
 	{
-	    if (!mImplPriv->mGeneralGroup)
-	    {
-		return;
-	    }
-	    
-	    class generalItemsVisitor : public SipConfigurationItemVisitor
-	    {
-	    public:
-	    private:
-	    } generalVisitor;
... 287 lines suppressed ...


-- 
asterisk-scf/integration/sip.git



More information about the asterisk-scf-commits mailing list