diff options
Diffstat (limited to 'configmgr/source/api/confevents.cxx')
-rw-r--r-- | configmgr/source/api/confevents.cxx | 299 |
1 files changed, 223 insertions, 76 deletions
diff --git a/configmgr/source/api/confevents.cxx b/configmgr/source/api/confevents.cxx index a1e4e59537..b99cd9b1f7 100644 --- a/configmgr/source/api/confevents.cxx +++ b/configmgr/source/api/confevents.cxx @@ -34,123 +34,270 @@ #include <stdio.h> #include <string.h> #include "confevents.hxx" -#include "confeventhelpers.hxx" +#include "configexcept.hxx" #include "treechangelist.hxx" #include <osl/diagnose.h> namespace configmgr { ///////////////////////////////////////////////////////////////////////// - using internal::ConfigChangesBroadcasterImpl; - - ///////////////////////////////////////////////////////////////////////// - class ConfigChangeBroadcastHelper // broadcasts changes for a given set of options - { - ConfigChangesBroadcasterImpl m_changes; - public: - ConfigChangeBroadcastHelper(); - ~ConfigChangeBroadcastHelper(); - - void broadcast(TreeChangeList const& anUpdate, sal_Bool bError, IConfigBroadcaster* pSource); - - public: - // IConfigBroadcaster implementation helper - void addListener(AbsolutePath const& aName, INodeListenerRef const& ); - void removeListener(INodeListenerRef const&); - - void dispose(IConfigBroadcaster* pSource); - }; - - ///////////////////////////////////////////////////////////////////////// - ConfigChangeBroadcaster::ConfigChangeBroadcaster() - { - } - - ConfigChangeBroadcaster::~ConfigChangeBroadcaster() - { - } - - ///////////////////////////////////////////////////////////////////////// ConfigChangeBroadcastHelper::ConfigChangeBroadcastHelper() - : m_changes() { } ConfigChangeBroadcastHelper::~ConfigChangeBroadcastHelper() { + OSL_ENSURE(m_aListeners.begin() == m_aListeners.end(), "Remaining listeners found - forgot to dispose ?"); + OSL_ENSURE(m_aPathMap.empty(), "Spurious mappings found"); } ///////////////////////////////////////////////////////////////////////// - void ConfigChangeBroadcastHelper::dispose(IConfigBroadcaster* pSource) + void ConfigChangeBroadcastHelper::dispose(TreeManager * pSource) { - m_changes.disposing(pSource); + disposing(pSource); } ///////////////////////////////////////////////////////////////////////// - // IConfigBroadcaster implementation - void ConfigChangeBroadcaster::addListener(AbsolutePath const& aName, RequestOptions const & _aOptions, INodeListenerRef const& pHandler) + void ConfigChangeBroadcastHelper::addListener(configuration::AbsolutePath const& aName, rtl::Reference<INodeListener> const& pHandler) { - if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(_aOptions,true)) - { - pHelper->addListener(aName, pHandler); - } - else - OSL_ASSERT(false); + add(aName, pHandler); } - void ConfigChangeBroadcaster::removeListener(RequestOptions const & _aOptions, INodeListenerRef const& pHandler) + void ConfigChangeBroadcastHelper::removeListener(rtl::Reference<INodeListener> const& pHandler) { - if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(_aOptions,false)) - { - pHelper->removeListener( pHandler); - } + remove(pHandler); } ///////////////////////////////////////////////////////////////////////// - void ConfigChangeBroadcaster::fireChanges(TreeChangeList const& rList_, sal_Bool bError_) + void ConfigChangeBroadcastHelper::broadcast(TreeChangeList const& anUpdate, sal_Bool bError, TreeManager * pSource) + { + dispatch(anUpdate, bError, pSource); + } + +///////////////////////////////////////////////////////////////////////// +void ConfigChangeBroadcastHelper::add(configuration::AbsolutePath const& aName, rtl::Reference<INodeListener> const& pListener) +{ + osl::MutexGuard aGuard(m_aListeners.mutex); + + internal::BroadcastImplHelper<internal::NodeListenerInfo>::Interfaces::iterator aAdded = m_aListeners.addListener(internal::NodeListenerInfo(pListener)); + aAdded->addPath(aName); + m_aPathMap.insert(PathMap::value_type(aName,aAdded)); +} + +///////////////////////////////////////////////////////////////////////// +void ConfigChangeBroadcastHelper::remove(rtl::Reference<INodeListener> const& pListener) +{ + osl::MutexGuard aGuard(m_aListeners.mutex); + + internal::BroadcastImplHelper<internal::NodeListenerInfo>::Interfaces::const_iterator const iter = m_aListeners.find(pListener); + if (iter != m_aListeners.end()) { - if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(rList_.getOptions(),false)) + internal::NodeListenerInfo::Pathes const& pathes = iter->pathList(); + + // first clear the Path Map + for(internal::NodeListenerInfo::Pathes::iterator itPath = pathes.begin(); itPath != pathes.end(); ++itPath) { - pHelper->broadcast(rList_, bError_, this); + std::pair<PathMap::iterator, PathMap::iterator> aRange = m_aPathMap.equal_range(*itPath); + while (aRange.first != aRange.second) + { + PathMap::iterator cur = aRange.first++; + if (cur->second == iter) + m_aPathMap.erase(cur); + } } + + // the remove the broadcast helper entry + m_aListeners.removeListener(pListener); } +} - ///////////////////////////////////////////////////////////////////////// - ConfigChangeBroadcastHelper* ConfigChangeBroadcaster::newBroadcastHelper() +///////////////////////////////////////////////////////////////////////// +// This should actually be available from the TreeChangeList +///////////////////////////////////////////////////////////////////////// + +static Change const* resolvePath(Change const& rChange, configuration::RelativePath& aRelativePath, RemoveNode const*& pRemoveNode) +{ + std::vector<configuration::Path::Component>::const_reverse_iterator aIter; + + OSL_ASSERT(pRemoveNode == NULL); + pRemoveNode = NULL; + + Change const* pChange = &rChange; + pRemoveNode = dynamic_cast<RemoveNode const*>(pChange); + + std::vector<configuration::Path::Component>::const_reverse_iterator const aEnd(aRelativePath.end()); + + for( aIter = aRelativePath.begin(); + aIter != aEnd; + ++aIter) { - return new ConfigChangeBroadcastHelper(); + OSL_ASSERT( pChange != NULL ); + + pChange = pChange->getSubChange(aIter->getName()); + + if (pChange == NULL) break; + + OSL_ASSERT(pRemoveNode == NULL); + OSL_ASSERT(aIter->getName() == pChange->getNodeName()); + + pRemoveNode = dynamic_cast<RemoveNode const*>(pChange); } - ///////////////////////////////////////////////////////////////////////// - void ConfigChangeBroadcaster::disposeBroadcastHelper(ConfigChangeBroadcastHelper* pHelper) + + if (pRemoveNode) { - if (pHelper) - { - pHelper->dispose(this); - delete pHelper; - } - } - ///////////////////////////////////////////////////////////////////////// - // IConfigBroadcaster implementation help - void ConfigChangeBroadcastHelper::addListener(AbsolutePath const& aName, INodeListenerRef const& pHandler) - { - m_changes.add(aName, pHandler); + aRelativePath = configuration::RelativePath( configuration::Path::Rep(aRelativePath.begin(),aIter) ); + OSL_ASSERT( aRelativePath.getLocalName().getName() == pRemoveNode->getNodeName()); } + else + OSL_ASSERT( pChange == 0 || configuration::matches(aRelativePath, configuration::RelativePath( configuration::Path::Rep(aRelativePath.begin(),aIter) )) ); + + return pChange; +} + +///////////////////////////////////////////////////////////////////////// +void ConfigChangeBroadcastHelper::dispatchInner +( + rtl::Reference<INodeListener> const& pTarget, + configuration::AbsolutePath const& _aTargetPath, + Change const& rBaseChange, + configuration::AbsolutePath const& _aChangeLocation, + sal_Bool , //_bError, + TreeManager * pSource +) +{ + try + { + OSL_ASSERT(pTarget.is()); + OSL_ASSERT( configuration::Path::hasPrefix( _aTargetPath, _aChangeLocation ) ); + + configuration::RelativePath aLocalPath = configuration::Path::stripPrefix( _aTargetPath, _aChangeLocation ); + + RemoveNode const* pRemoved = 0; + Change const* pTargetChange = resolvePath(rBaseChange, aLocalPath, pRemoved ); + + OSL_ASSERT( !pTargetChange || matches(_aChangeLocation.compose(aLocalPath),_aTargetPath) ); + + if (pRemoved) + pTarget->nodeDeleted(_aChangeLocation.compose(aLocalPath), pSource); + + else if (pTargetChange) + pTarget->nodeChanged(*pTargetChange, _aTargetPath, pSource); - void ConfigChangeBroadcastHelper::removeListener(INodeListenerRef const& pHandler) - { - m_changes.remove(pHandler); } + catch (configuration::InvalidName& ) + { + OSL_ENSURE(false,"ConfigChangeBroadcastHelper: Could not dispatch notification: context path mismatch"); + } +} -/* void ConfigChangeBroadcastHelper::removeNode(OUString const& aPath, bool bRemovedFromModel, IConfigBroadcaster* pSource) - { - m_changes.removed(aPath, bRemovedFromModel,pSource); +///////////////////////////////////////////////////////////////////////// +void ConfigChangeBroadcastHelper::dispatchOuter +( + rtl::Reference<INodeListener> const& pTarget, + configuration::AbsolutePath const& _aTargetPath, + Change const& rBaseChange, + configuration::AbsolutePath const& _aChangeLocation, + sal_Bool , //_bError, + TreeManager * pSource +) +{ + { (void)_aTargetPath; } + OSL_ASSERT(pTarget.is()); + OSL_ASSERT( configuration::Path::hasPrefix( _aChangeLocation, _aTargetPath) ); + + pTarget->nodeChanged(rBaseChange, _aChangeLocation, pSource); +} + +///////////////////////////////////////////////////////////////////////// +void ConfigChangeBroadcastHelper::dispatch(TreeChangeList const& rList_, sal_Bool _bError, TreeManager * pSource) +{ + dispatch(rList_.root, rList_.getRootNodePath(),_bError, pSource); +} + +///////////////////////////////////////////////////////////////////////// +namespace +{ + struct DispatchTarget + { + DispatchTarget(rtl::Reference<INodeListener> _pTarget, configuration::AbsolutePath const* _pDispatchPath) + : pTarget(_pTarget), pDispatchPath( _pDispatchPath) {} + + rtl::Reference<INodeListener> pTarget; + configuration::AbsolutePath const* pDispatchPath; + }; +} +///////////////////////////////////////////////////////////////////////// +void ConfigChangeBroadcastHelper::dispatch +( + Change const& rBaseChange, + configuration::AbsolutePath const& _aChangeLocation, + sal_Bool _bError, + TreeManager * pSource +) +{ + OSL_ENSURE(!_aChangeLocation.isRoot(),"Cannot dispatch changes directly to the root node"); + + // listeners registered under multiple sub-pathes will be called multiple times ! + + // Collect the targets + osl::ClearableMutexGuard aGuard(m_aListeners.mutex); + + // Dispatch listeners to ancestors of the change root + std::vector<DispatchTarget> aOuterTargets; + if (_aChangeLocation.getDepth() > 1) + { + configuration::AbsolutePath const aModulePath( configuration::Path::Rep(*_aChangeLocation.begin()) ); + + PathMap::const_iterator itOuter = m_aPathMap.lower_bound( aModulePath ); + PathMap::const_iterator const endOuter = m_aPathMap.upper_bound(_aChangeLocation.getParentPath()); + + // TODO: Both loops are so similar - they should be a single function + while (itOuter != endOuter) + { + OSL_ASSERT( m_aListeners.find(itOuter->second->get()) != m_aListeners.end() ); + + // check whether this should be dispatched at all + if ( configuration::Path::hasPrefix(_aChangeLocation,itOuter->first) ) + { + aOuterTargets.push_back( DispatchTarget(itOuter->second->get(), &itOuter->first) ); + } + ++itOuter; + } } -*/ - ///////////////////////////////////////////////////////////////////////// - void ConfigChangeBroadcastHelper::broadcast(TreeChangeList const& anUpdate, sal_Bool bError, IConfigBroadcaster* pSource) + + // Dispatch listeners to descendants of the change root + std::vector<DispatchTarget> aInnerTargets; { - m_changes.dispatch(anUpdate, bError, pSource); + PathMap::const_iterator itInner = m_aPathMap.lower_bound(_aChangeLocation); + + while( itInner != m_aPathMap.end() && configuration::Path::hasPrefix(itInner->first,_aChangeLocation) ) + { + OSL_ASSERT( m_aListeners.find(itInner->second->get()) != m_aListeners.end() ); + + aInnerTargets.push_back( DispatchTarget(itInner->second->get(), &itInner->first) ); + + ++itInner; + } } + aGuard.clear(); + + {for (std::vector<DispatchTarget>::const_iterator it = aOuterTargets.begin(); it != aOuterTargets.end(); ++it){ + this->dispatchOuter(it->pTarget, *it->pDispatchPath, rBaseChange, _aChangeLocation, _bError, pSource); + }} + {for (std::vector<DispatchTarget>::const_iterator it = aInnerTargets.begin(); it != aInnerTargets.end(); ++it){ + this->dispatchInner(it->pTarget, *it->pDispatchPath, rBaseChange, _aChangeLocation, _bError, pSource); + }} +} + +///////////////////////////////////////////////////////////////////////// +void ConfigChangeBroadcastHelper::disposing(TreeManager * pSource) +{ + osl::ClearableMutexGuard aGuard(m_aListeners.mutex); + m_aPathMap.clear(); + + aGuard.clear(); + m_aListeners.disposing(pSource); +} } // namespace |