summaryrefslogtreecommitdiff
path: root/configmgr/source/api/confeventhelpers.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'configmgr/source/api/confeventhelpers.cxx')
-rw-r--r--configmgr/source/api/confeventhelpers.cxx484
1 files changed, 484 insertions, 0 deletions
diff --git a/configmgr/source/api/confeventhelpers.cxx b/configmgr/source/api/confeventhelpers.cxx
new file mode 100644
index 000000000000..ef2ea4ee13a3
--- /dev/null
+++ b/configmgr/source/api/confeventhelpers.cxx
@@ -0,0 +1,484 @@
+/*************************************************************************
+ *
+ * $RCSfile: confeventhelpers.cxx,v $
+ *
+ * $Revision: 1.1.1.1 $
+ *
+ * last change: $Author: hr $ $Date: 2000-09-18 16:13:40 $
+ *
+ * The Contents of this file are made available subject to the terms of
+ * either of the following licenses
+ *
+ * - GNU Lesser General Public License Version 2.1
+ * - Sun Industry Standards Source License Version 1.1
+ *
+ * Sun Microsystems Inc., October, 2000
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2000 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ *
+ * Sun Industry Standards Source License Version 1.1
+ * =================================================
+ * The contents of this file are subject to the Sun Industry Standards
+ * Source License Version 1.1 (the "License"); You may not use this file
+ * except in compliance with the License. You may obtain a copy of the
+ * License at http://www.openoffice.org/license.html.
+ *
+ * Software provided under this License is provided on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+ * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
+ * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
+ * See the License for the specific provisions governing your rights and
+ * obligations concerning the Software.
+ *
+ * The Initial Developer of the Original Code is: Sun Microsystems, Inc.
+ *
+ * Copyright: 2000 by Sun Microsystems, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * Contributor(s): _______________________________________
+ *
+ *
+ ************************************************************************/
+
+#include <stdio.h>
+#include "confeventhelpers.hxx"
+
+#ifndef CONFIGMGR_CONFNAME_HXX_
+#include "confname.hxx"
+#endif
+
+#ifndef _OSL_DIAGNOSE_H_
+#include <osl/diagnose.h>
+#endif
+
+namespace configmgr
+{
+ namespace internal
+ {
+
+ void throwDispatchIllegalSequenceException()
+ {
+ OSL_ENSHURE( 0, "Illegal Call to brodcaster while dispatching" );
+ }
+
+////////////////////////////////////////////////////////////////////////
+/* template <class Listener>
+ class BroadcastImplHelper
+ {
+ public:
+ osl::Mutex m_aMutex;
+
+ BroadcastImplHelper() {}
+ ~BroadcastImplHelper() {}
+
+ typedef std::set<Listener*> Interfaces;
+ typedef Interfaces::const_iterator Iterator;
+
+ void addInterface(Listener* aListener) { m_aInterfaces.insert(aListener); }
+ void removeInterface(Listener* aListener) { m_aInterfaces.erase(aListener); }
+
+ void disposing(ConfigChangeBroadcaster* pSource);
+
+ Iterator begin() const { return m_aInterfaces.begin(); }
+ Iterator end() const { return m_aInterfaces.end(); }
+ private:
+ Interfaces m_aInterfaces;
+
+ // no implementation - not copyable
+ BroadcastImplHelper(BroadcastImplHelper&);
+ void operator=(BroadcastImplHelper&);
+ };
+*/
+
+/////////////////////////////////////////////////////////////////////////
+/*
+ struct NodeListenerInfo
+ {
+ INodeListener* m_pListener;
+ OUString m_path;
+
+ // fake a pointer for generic clients
+ INodeListener* operator->() const { return m_pListener; }
+ INodeListener& operator*() const { return *m_pListener; }
+
+ bool operator < (NodeListenerInfo const& aInfo) const;
+ };
+*/
+/////////////////////////////////////////////////////////////////////////
+
+/*
+ class ConfigChangesBroadcasterImpl
+ {
+ private:
+ typedef BroadcastImplHelper<NodeListenerInfo> Listeners;
+ Listeners m_aListeners;
+ std::map<OUString, Listeners::Iterator> m_aDispatchInfos;
+ };
+*/
+/////////////////////////////////////////////////////////////////////////
+ConfigChangesBroadcasterImpl::ConfigChangesBroadcasterImpl()
+{
+}
+
+/////////////////////////////////////////////////////////////////////////
+ConfigChangesBroadcasterImpl::~ConfigChangesBroadcasterImpl()
+{
+ OSL_ENSURE(m_aListeners.begin() == m_aListeners.end(), "Remaining listeners found - forgot to dispose ?");
+ OSL_ENSURE(m_aPathMap.empty(), "Spurious mappings found");
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangesBroadcasterImpl::add(OUString const& aName, INodeListener* pListener)
+{
+ OSL_ASSERT( ! ConfigurationName(aName).isRelative() );
+
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ InfoRef aAdded = m_aListeners.addListener(NodeListenerInfo(pListener));
+ aAdded->addPath(aName);
+ m_aPathMap.insert(PathMap::value_type(aName,aAdded));
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangesBroadcasterImpl::remove(INodeListener* pListener)
+{
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ Listeners::Iterator const iter = m_aListeners.find(pListener);
+ if (iter != m_aListeners.end())
+ {
+ typedef NodeListenerInfo::Pathes Pathes;
+ Pathes const& pathes = iter->pathList();
+
+ // first clear the Path Map
+ for(Pathes::iterator itPath = pathes.begin(); itPath != pathes.end(); ++itPath)
+ {
+ typedef PathMap::iterator PMIter;
+ typedef std::pair<PMIter, PMIter> PMRange;
+
+ PMRange aRange = m_aPathMap.equal_range(*itPath);
+ while (aRange.first != aRange.second)
+ {
+ PMIter cur = aRange.first++;
+ if (cur->second == iter)
+ m_aPathMap.erase(cur);
+ }
+ }
+
+ // the remove the broadcast helper entry
+ m_aListeners.removeListener(pListener);
+ }
+}
+
+void ConfigChangesBroadcasterImpl::removed(OUString const& aBasePath, bool bRemovedFromModel, IConfigBroadcaster* pSource)
+{
+ OSL_ASSERT( ! ConfigurationName(aBasePath).isRelative() );
+
+ // Dispatch 'deleted' to descendants of the changed path
+
+ for( PathMap::const_iterator it = m_aPathMap.lower_bound(aBasePath);
+ it != m_aPathMap.end() && 0 == aBasePath.compareTo(it->first, aBasePath.getLength());
+ )
+ {
+ OSL_ASSERT( m_aListeners.find(it->second->get()) != m_aListeners.end() );
+
+ OUString aDispatchPath = it->first;
+ OSL_ASSERT( ! ConfigurationName(aDispatchPath).isRelative() );
+
+ INodeListener* pTarget = it->second->get();
+ ++it;
+
+ // we allow a listener to remove itself from within the callback
+ // the simple increment above wont work, if the following listener is the same listener
+ // (which really shouldn't happen)
+ PathMap::const_iterator next = it;
+ while (next != m_aPathMap.end() && next->second->get() == pTarget)
+ ++next;
+
+ pTarget->nodeDeleted(aBasePath, pSource);
+
+ // if a listener removes itself from within the callback, it will be missing by now
+ // so we check whether our listener is still there and if necessary patch our position
+ if (m_aListeners.find(pTarget) == m_aListeners.end())
+ it = next;
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////
+// This should actually be available from the TreeChangeList
+/////////////////////////////////////////////////////////////////////////
+
+static Change const* resolvePath(Change const* pChange, ConfigurationName& aRelativePath, RemoveNode const*& pRemoveNode)
+{
+ OSL_ASSERT(aRelativePath.isRelative());
+ OSL_ASSERT(pRemoveNode == 0);
+ pRemoveNode = 0;
+
+ ConfigurationName::Iterator aIter(aRelativePath.begin());
+ ConfigurationName::Iterator const aEnd(aRelativePath.end());
+
+ OSL_ASSERT(pChange);
+ OSL_ASSERT(aIter != aEnd);
+
+ while (pChange)
+ {
+ if (pChange->ISA(RemoveNode))
+ pRemoveNode = static_cast<RemoveNode const*>(pChange);
+
+ OSL_ASSERT(*aIter == pChange->getNodeName());
+ if (++aIter == aEnd)
+ break; // found it
+
+ pChange = pChange->getSubChange(*aIter);
+
+ OSL_ASSERT(pRemoveNode == NULL || pChange == NULL);
+ }
+ if (pRemoveNode)
+ {
+ aRelativePath = ConfigurationName(aRelativePath.begin(),aIter);
+ OSL_ASSERT( aRelativePath.localName() == pRemoveNode->getNodeName());
+ }
+ else
+ OSL_ASSERT(pChange == 0 || aRelativePath == ConfigurationName(aRelativePath.begin(),aIter));
+
+ return pChange;
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangesBroadcasterImpl::dispatchInner
+(
+ INodeListener* pTarget,
+ OUString const& sTargetPath,
+ Change const& rBaseChange,
+ OUString const& sChangeContext,
+ sal_Bool , //_bError,
+ IConfigBroadcaster* pSource
+)
+{
+ ConfigurationName aContext(sChangeContext);
+
+ OSL_ASSERT(pTarget);
+ OSL_ASSERT( ConfigurationName(sTargetPath).isNestedIn( aContext ) );
+
+ ConfigurationName aLocalPath = ConfigurationName(sTargetPath).relativeTo( aContext );
+ RemoveNode const* pRemoved = 0;
+ Change const* pTargetChange = resolvePath(&rBaseChange, aLocalPath, pRemoved );
+
+ if (pRemoved)
+ {
+ pTarget->nodeDeleted(aContext.composeWith(aLocalPath).fullName(), pSource);
+ }
+ else if (pTargetChange)
+ {
+ OSL_ASSERT(aContext.composeWith(aLocalPath) == sTargetPath);
+ pTarget->nodeChanged(*pTargetChange, sTargetPath, pSource);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangesBroadcasterImpl::dispatchOuter
+(
+ INodeListener* pTarget,
+ OUString const& sTargetPath,
+ Change const& rBaseChange,
+ OUString const& sChangeContext,
+ sal_Bool , //_bError,
+ IConfigBroadcaster* pSource
+)
+{
+ ConfigurationName sChangesRoot(sChangeContext,rBaseChange.getNodeName());
+
+ OSL_ASSERT(pTarget);
+ OSL_ASSERT( sChangesRoot.isNestedIn( sTargetPath ) );
+
+ pTarget->nodeChanged(rBaseChange, sChangesRoot.fullName(), pSource);
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangesBroadcasterImpl::dispatch(TreeChangeList const& rList_, sal_Bool _bError, IConfigBroadcaster* pSource)
+{
+ dispatch(rList_.root, rList_.pathToRoot,_bError, pSource);
+}
+void ConfigChangesBroadcasterImpl::dispatch
+(
+ Change const& rBaseChange,
+ OUString const& sChangeContext,
+ sal_Bool _bError,
+ IConfigBroadcaster* pSource
+)
+{
+ // listeners registered under multiple sub-pathes will be called multiple times !
+
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ ConfigurationName aRootName(sChangeContext);
+ OSL_ASSERT(!aRootName.isRelative());
+
+ ConfigurationName aNodeName(aRootName, rBaseChange.getNodeName());
+ OUString aBasePath( aNodeName.fullName() );
+ OSL_ASSERT(!aNodeName.isRelative());
+
+ OSL_ASSERT(aNodeName.getParentName() == aRootName);
+
+ // Dispatch listeners to ancestors of the change root
+ PathMap::const_iterator const endOuter = m_aPathMap.upper_bound(aRootName.fullName());
+
+ // TODO: Both loops are so similar - they should be a single function
+ for ( PathMap::const_iterator itOuter = m_aPathMap.lower_bound( ConfigurationName::rootname() += aRootName.moduleName() );
+ itOuter != endOuter;
+ )
+ {
+ OSL_ASSERT( m_aListeners.find(itOuter->second->get()) != m_aListeners.end() );
+
+ OUString aDispatchPath = itOuter->first;
+ OSL_ASSERT( ! ConfigurationName(aDispatchPath).isRelative() );
+
+ INodeListener* pTarget = itOuter->second->get();
+
+ // incrementing here usually is enough
+ ++itOuter;
+
+ // check whether this should be dispatched at all
+ if (aBasePath == aDispatchPath || aNodeName.isNestedIn(aDispatchPath))
+ {
+ // we allow a listener to remove itself from within the callback
+ // the simple increment above wont work, if the following listener is the same listener
+ // (which really shouldn't happen)
+ PathMap::const_iterator next = itOuter;
+ while (next != m_aPathMap.end() && next->second->get() == pTarget)
+ ++next;
+
+ this->dispatchOuter(pTarget, aDispatchPath, rBaseChange, sChangeContext, _bError, pSource);
+
+ // if a listener removes itself from within the callback, it will be missing by now
+ // so we check whether our listener is still there and if necessary patch our position
+ if (m_aListeners.find(pTarget) == m_aListeners.end())
+ itOuter = next;
+ }
+ }
+
+
+ // Dispatch listeners to descendants of the change root
+ for( PathMap::const_iterator itInner = m_aPathMap.lower_bound(aBasePath);
+ itInner != m_aPathMap.end() && 0 == aBasePath.compareTo(itInner->first, aBasePath.getLength());
+ )
+ {
+ OSL_ASSERT( m_aListeners.find(itInner->second->get()) != m_aListeners.end() );
+
+ OUString aDispatchPath = itInner->first;
+ OSL_ASSERT( ! ConfigurationName(aDispatchPath).isRelative() );
+
+ INodeListener* pTarget = itInner->second->get();
+ ++itInner;
+
+ // check whether this should be dispatched at all
+ if (aBasePath == aDispatchPath || ConfigurationName(aDispatchPath).isNestedIn(aRootName))
+ {
+ // we allow a listener to remove itself from within the callback
+ // the simple increment above wont work, if the following listener is the same listener
+ // (which really shouldn't happen)
+ PathMap::const_iterator next = itInner;
+ while (next != m_aPathMap.end() && next->second->get() == pTarget)
+ ++next;
+
+ this->dispatchInner(pTarget, aDispatchPath, rBaseChange, sChangeContext, _bError, pSource);
+
+ // if a listener removes itself from within the callback, it will be missing by now
+ // so we check whether our listener is still there and if necessary patch our position
+ if (m_aListeners.find(pTarget) == m_aListeners.end())
+ itInner = next;
+ }
+
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigChangesBroadcasterImpl::disposing(IConfigBroadcaster* pSource)
+{
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ m_aPathMap.clear();
+ m_aListeners.disposing(pSource);
+}
+
+/////////////////////////////////////////////////////////////////////////
+/* class ConfigMessageBroadcasterImpl
+ {
+ public:
+ private:
+ typedef BroadcastImplHelper<INodeListener*> Listeners;
+ Listeners m_aListeners;
+ };
+*/
+/////////////////////////////////////////////////////////////////////////
+void ConfigMessageBroadcasterImpl::add(IMessageHandler* pListener)
+{
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ m_aListeners.addListener(pListener);
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigMessageBroadcasterImpl::remove(IMessageHandler* pListener)
+{
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ m_aListeners.removeListener(pListener);
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigMessageBroadcasterImpl::dispatch(OUString const& _rNotifyReason, sal_Int32 _nNotificationId, IConfigBroadcaster* pSource)
+{
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ for (Listeners::Iterator it = m_aListeners.begin(); it != m_aListeners.end(); )
+ {
+ // incrementing here allows a listener to remove itself from within the callback
+
+ // it is illegal to cause removal of another listener from the callback
+ // if this occurs (dereferencing, incrementing or comparing 'it' fails)
+ // we need to explicitly guard against that (which is really too expensive)
+
+ IMessageHandler* pHandler = *it;
+ ++it;
+
+ if (pHandler)
+ pHandler->message(_rNotifyReason,_nNotificationId,pSource);
+ }
+
+}
+
+/////////////////////////////////////////////////////////////////////////
+void ConfigMessageBroadcasterImpl::disposing(IConfigBroadcaster* pSource)
+{
+ osl::MutexGuard aGuard(m_aListeners.mutex);
+
+ m_aListeners.disposing(pSource);
+}
+
+/////////////////////////////////////////////////////////////////////////
+ } // namespace
+} // namespace
+
+
+