diff options
-rw-r--r-- | configmgr/source/tree/cmtree.cxx | 452 |
1 files changed, 328 insertions, 124 deletions
diff --git a/configmgr/source/tree/cmtree.cxx b/configmgr/source/tree/cmtree.cxx index 1b18edc7d9fc..8d00089430e4 100644 --- a/configmgr/source/tree/cmtree.cxx +++ b/configmgr/source/tree/cmtree.cxx @@ -2,9 +2,9 @@ * * $RCSfile: cmtree.cxx,v $ * - * $Revision: 1.2 $ + * $Revision: 1.3 $ * - * last change: $Author: fs $ $Date: 2000-10-18 15:53:24 $ + * last change: $Author: dg $ $Date: 2000-10-24 11:07:56 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -80,6 +80,9 @@ #ifndef _CONFIGMGR_TREEACCESS_HXX_ #include "treeaccess.hxx" #endif +#ifndef CONFIGMGR_API_CHANGESSET_HXX_ +#include "confchangesset.hxx" +#endif // WISDOM // !!Never write same code twice!! @@ -148,12 +151,10 @@ namespace configmgr Subtree::Subtree(OUString const& aName) :ISubtree(aName) ,m_nLevel(0) - ,m_bComplete(sal_False) { } Subtree::Subtree() :m_nLevel(0) - ,m_bComplete(sal_False) { } Subtree::~Subtree() {} @@ -263,6 +264,11 @@ namespace configmgr return aReturn; } + //========================================================================== + //= OPropagateLevels + //========================================================================== + /** fills a subtree with the correct level informations + */ struct OPropagateLevels : public NodeModification { protected: @@ -275,14 +281,222 @@ namespace configmgr virtual void handle(ValueNode&) { /* not interested in value nodes */ } virtual void handle(ISubtree& _rSubtree) { - if ((ITreeProvider::ALL_LEVELS == nChildLevel) || (nChildLevel > 0)) + if ((ITreeProvider::ALL_LEVELS == nChildLevel) || nChildLevel > _rSubtree.getLevel()) + _rSubtree.setLevel(nChildLevel); + } + }; + + //========================================================================== + //= OCompleteTree + //========================================================================== + /** completes the cache with missing subelements + */ + struct OCompleteTree : public NodeModification + { + protected: + ISubtree* m_pCacheSubtree; + sal_Int32 m_nChildLevel; + + public: + OCompleteTree(ISubtree* pSubtree, sal_Int32 _nParentLevel) + :m_pCacheSubtree(pSubtree) + { + m_nChildLevel = (ITreeProvider::ALL_LEVELS == _nParentLevel) ? ITreeProvider::ALL_LEVELS : _nParentLevel - 1; + } + virtual void handle(ValueNode&) { /* not interested in value nodes */ } + virtual void handle(ISubtree& _rSubtree) + { + OUString aNodeName = _rSubtree.getName(); + INode* pChild = m_pCacheSubtree->getChild(aNodeName); + // now we have different possibilites + // a.) the node does not exist than clone the subtree and add it to the cache tree + if (!pChild) + { + pChild = _rSubtree.clone(); + ISubtree* pSubTree = pChild->asISubtree(); + m_pCacheSubtree->addChild(::std::auto_ptr<INode>(pSubTree)); + } + else + { + ISubtree* pSubTree = pChild->asISubtree(); + OSL_ENSHURE(pSubTree, "OCompleteTree::handle : node must be a inner node!"); + + // b.) the node does exist with level all or greater level -> nothing to do + // c.) the node does exist but with smaller level + if (pSubTree && ITreeProvider::ALL_LEVELS != pSubTree->getLevel() && + (ITreeProvider::ALL_LEVELS == m_nChildLevel || + m_nChildLevel > pSubTree->getLevel())) + { + OCompleteTree aNextLevel(pSubTree, m_nChildLevel); + aNextLevel.applyToChildren(_rSubtree); + } + } + } + }; + + //========================================================================== + //= OBuildChangeTree + //========================================================================== + /** generates a change tree by comparing two trees + */ + struct OBuildChangeTree : public NodeModification + { + protected: + SubtreeChange& m_rChangeList; + INode* m_pCacheNode; + + public: + OBuildChangeTree(SubtreeChange& rList, INode* pNode) + :m_rChangeList(rList) + ,m_pCacheNode(pNode) + { + } + + virtual void handle(ValueNode& _nNode) + { + OUString aNodeName = _nNode.getName(); + ISubtree* pTree = m_pCacheNode->asISubtree(); + OSL_ENSHURE(pTree, "OBuildChangeTree::handle : node must be a inner node!"); + if (pTree) + { + INode* pChild = pTree->getChild(aNodeName); + ValueNode* pValueNode = pChild ? pChild->asValueNode() : NULL; + OSL_ENSHURE(pValueNode, "OBuildChangeTree::handle : node must be a value node!"); + + // if the values differ add a new change + if (pValueNode && _nNode.getValue() != pValueNode->getValue()) + { + ValueChange* pChange = new ValueChange(_nNode.getValue(), *pValueNode); + m_rChangeList.addChange(::std::auto_ptr<Change>(pChange)); + } + } + } + + virtual void handle(ISubtree& _rSubtree) + { + OUString aNodeName = _rSubtree.getName(); + ISubtree* pTree = m_pCacheNode->asISubtree(); + OSL_ENSHURE(pTree, "OBuildChangeTree::handle : node must be a inner node!"); + if (pTree) { - OPropagateLevels aDeeperInto(nChildLevel); - aDeeperInto.applyToChildren(_rSubtree); + INode* pChild = pTree->getChild(aNodeName); + // node not in cache, so ignore it + // later, when we get additions and removements within on transaction, then we have to care about + if (pChild) + { + ISubtree* pSubTree = pChild->asISubtree(); + OSL_ENSHURE(pSubTree, "OBuildChangeTree::handle : node must be a inner node!"); + // generate a new change + + SubtreeChange* pChange = new SubtreeChange(aNodeName); + OBuildChangeTree aNextLevel(*pChange, pSubTree); + aNextLevel.applyToChildren(_rSubtree); + + // now count if there are any changes + OChangeCounter aCounter; + pChange->dispatch(aCounter); + + if (aCounter.nCount != 0) + m_rChangeList.addChange(::std::auto_ptr<Change>(pChange)); + else + delete pChange; + } } } }; + // --------------------------------- updateTree --------------------------------- + class TreeUpdate : public ChangeTreeModification + { + ISubtree* m_pCurrentSubtree; +#if DBUG + std::vector<OString> aLog; +#endif + + public: + TreeUpdate(ISubtree* pSubtree):m_pCurrentSubtree(pSubtree){} + + void handle(ValueChange& aValueNode); + void handle(AddNode& aAddNode); + void handle(RemoveNode& aRemoveNode); + void handle(SubtreeChange& aSubtree); + }; + + void TreeUpdate::handle(ValueChange& aValueNode) + { + // Change a Value + OSL_ENSURE(m_pCurrentSubtree,"Cannot apply ValueChange without subtree"); + + INode* pBaseNode = m_pCurrentSubtree ? m_pCurrentSubtree->getChild(aValueNode.getNodeName()) : 0; + OSL_ENSURE(pBaseNode,"Cannot apply Change: No node to change"); + + ValueNode* pValue = pBaseNode ? pBaseNode->asValueNode() : 0; + OSL_ENSURE(pValue,"Cannot apply ValueChange: Node is not a value"); + + if (pValue) + aValueNode.applyTo(*pValue); +#ifdef DBUG + else + { + ::rtl::OString aStr("TreeUpdate: Can't find value with name:="); + aStr += rtl::OUStringToOString(aValueNode.getNodeName(),RTL_TEXTENCODING_ASCII_US); + OSL_ENSHURE(pValue, aStr.getStr()); + aLog.push_back(aStr); + } +#endif + } + + void TreeUpdate::handle(AddNode& aAddNode) + { + // Add a new Value + if (m_pCurrentSubtree) + m_pCurrentSubtree->addChild(aAddNode.releaseAddedNode()); +#ifdef DBUG + else + aLog.push_back(OString("TreeUpdate: no CurrentSubtree for AddNode")); +#endif + + } + + void TreeUpdate::handle(RemoveNode& aRemoveNode) + { + // remove a Value + if (m_pCurrentSubtree) + { + sal_Bool bOk = (NULL != m_pCurrentSubtree->removeChild(aRemoveNode.getNodeName()).get()); + +#ifdef DBUG + ::rtl::OString aStr("TreeUpdate: Can't remove child with name:="); + aStr += rtl::OUStringToOString(aRemoveNode.getNodeName(),RTL_TEXTENCODING_ASCII_US); + OSL_ENSHURE(bOk, aStr.getStr()); + if (!bOk) + aLog.push_back(aStr); +#endif + } + } + + + void TreeUpdate::handle(SubtreeChange& aSubtree) + { + // handle traversion + ISubtree *pOldSubtree = m_pCurrentSubtree; + OSL_ENSHURE(m_pCurrentSubtree->getChild(aSubtree.getNodeName()), "TreeUpdate::handle : invalid subtree change ... this will crash !"); + m_pCurrentSubtree = m_pCurrentSubtree->getChild(aSubtree.getNodeName())->asISubtree(); + +#if DBUG + ::rtl::OString aStr("TreeUpdate: there is no Subtree for name:="); + aStr += rtl::OUStringToOString(aSubtree.getNodeName(),RTL_TEXTENCODING_ASCII_US); + OSL_ENSHURE(m_pCurrentSubtree, aStr.getStr()); + if (!m_pCurrentSubtree) + aLog.push_back(aStr); +#endif + + aSubtree.forEachChange(*this); + m_pCurrentSubtree = pOldSubtree; + } + + + //-------------------------------------------------------------------------- void Subtree::setLevel(sal_Int16 _nLevel) { m_nLevel = _nLevel; @@ -295,6 +509,9 @@ namespace configmgr aDeeperInto.applyToChildren(*this); } + //-------------------------------------------------------------------------- + sal_Int16 Subtree::getLevel() const {return m_nLevel;} + void Subtree::forEachChild(NodeAction& anAction) const { for(ChildList::const_iterator it = m_aChildren.GetSet().begin(); it != m_aChildren.GetSet().end(); @@ -460,6 +677,13 @@ namespace configmgr // INode* pResult = m_pRoot->getChild(aComponentName); // return pResult->asISubtree(); + // looking for the requested subtree: results are + // a.) tree not found, tree isn't already cached + // b.) tree found, but not complete + // c.) tree found and complete + + sal_Bool bCompleteForRequest = sal_False; + // Build SearchName OSL_ENSHURE(m_pRoot, "Tree::requestSubtree : m_pRoot MUST NOT BE ZERO"); // hey, don't cry that loud .... @@ -473,18 +697,21 @@ namespace configmgr if (pSubtree) { INode* pNode = pSubtree->getChild(*it); - if (!pNode) + if (pNode) + pSubtree = pNode->asISubtree(); + else return NULL; - - pSubtree = pNode->asISubtree(); } else break; } - if (pSubtree && (ALL_LEVELS != pSubtree->getLevel()) && (nLevel > pSubtree->getLevel())) - pSubtree = NULL; - return pSubtree; + // if the tree is not complete: ALL_LEVELS != pSubtree->getLevel() + // or not fetched with all requested levels, we have to refetch + bCompleteForRequest = pSubtree && (ALL_LEVELS == pSubtree->getLevel() || + (ALL_LEVELS != nLevel && nLevel <= pSubtree->getLevel())); + + return bCompleteForRequest ? pSubtree : NULL; } // ----------------------------------------------------------------------------- @@ -565,144 +792,121 @@ namespace configmgr */ } - Subtree * Tree::addSubtree(const ConfigurationName& _rLocation, std::auto_ptr<Subtree> _pSubtree, sal_Int16 nLevels) + ISubtree* Tree::addSubtree(const ConfigurationName& _rLocation, std::auto_ptr<ISubtree> _pSubtree, sal_Int16 nLevels) { OSL_ENSHURE(nLevels != 0, "Tree::addSubtree : invalid level count !"); - // there was a time where 0 meant "all levels", but we changed the according enum in ITReeProvider - // so that it is -1 now. Since this time, 0 isn't valid as level depth anymore ! + // there was a time where 0 meant "all levels", but we changed the according enum in ITReeProvider + // so that it is -1 now. Since this time, 0 isn't valid as level depth anymore ! - auto_ptr<INode> pNode; + // if we notice that a subtree already exists we have to verify + // if the subtree is already complete populated - // look for the place where to insert the given node - ConfigurationName::Iterator aGoDown = _rLocation.begin(); - ConfigurationName::Iterator aStopAt = _rLocation.end(); - Subtree* pInsertInto = m_pRoot; - while (aGoDown != aStopAt) - { - OUString sCurrentName = *aGoDown; - ++aGoDown; + // do we already have the subtree in cache, but not completely populated? + // so find the subtree + Subtree* pEntry = m_pRoot; + for (ConfigurationName::Iterator i = _rLocation.begin(); i != _rLocation.end() && pEntry != NULL; i++) + pEntry = static_cast<Subtree*>(pEntry->getChild(*i)); - Subtree* pExistentSubtree = static_cast<Subtree*>(pInsertInto->getChild(sCurrentName)); - if (!pExistentSubtree) + // we already have a tree, so we fill the subtree with the neccessary fragments + if (pEntry) + { + OSL_ENSHURE(pEntry->getLevel() != ITreeProvider::ALL_LEVELS, "Tree::addSubtree : node already complete in cache, why adding it again? !"); + if (pEntry->getLevel() != ITreeProvider::ALL_LEVELS) { - Subtree* pNewChild = NULL; - if (aGoDown != aStopAt) - { // we already incremented aGoDown, so this means we still have (at least) one level to go - // -> we need a new temporary node - pNewChild = new Subtree(sCurrentName); - pNewChild = static_cast<Subtree*>(pInsertInto->addChild(::std::auto_ptr<INode>(pNewChild))); - pNewChild->setLevel(0); // which means "we know nothing about any children" - } - else - { // at this last level, we don't need an intermediate node, instead we have to insert _pSubtree here - break; - } - pExistentSubtree = pNewChild; + // release the ownership and delete that unnecessary tree + OCompleteTree aTreeCompletion(pEntry, nLevels); + aTreeCompletion.applyToChildren(*_pSubtree.get()); + + // now adjust the levels + pEntry->setLevel(nLevels); } - // one level down - pInsertInto = pExistentSubtree; + // release the ownership and delete that unnecessary tree + _pSubtree.release(); + delete _pSubtree.get(); + return pEntry; } - - Subtree* pNewSubtree = static_cast<Subtree*>(pInsertInto->addChild(::std::auto_ptr<INode>(_pSubtree.release()))); - pNewSubtree->setLevel(nLevels); - return pNewSubtree; - } - - - // --------------------------------- updateTree --------------------------------- - class TreeUpdate : public ChangeTreeModification - { - ISubtree* m_pCurrentSubtree; - std::vector<OString> aLog; - - public: - TreeUpdate(ISubtree* pSubtree):m_pCurrentSubtree(pSubtree){} - - void handle(ValueChange& aValueNode); - void handle(AddNode& aAddNode); - void handle(RemoveNode& aRemoveNode); - void handle(SubtreeChange& aSubtree); - }; - - void TreeUpdate::handle(ValueChange& aValueNode) - { - // Change a Value - OSL_ENSURE(m_pCurrentSubtree,"Cannot apply ValueChange without subtree"); - - INode* pBaseNode = m_pCurrentSubtree ? m_pCurrentSubtree->getChild(aValueNode.getNodeName()) : 0; - OSL_ENSURE(pBaseNode,"Cannot apply Change: No node to change"); - - ValueNode* pValue = pBaseNode ? pBaseNode->asValueNode() : 0; - OSL_ENSURE(pValue,"Cannot apply ValueChange: Node is not a value"); - - if (pValue) - aValueNode.applyTo(*pValue); -#ifdef DBUG else { - ::rtl::OString aStr("TreeUpdate: Can't find value with name:="); - aStr += rtl::OUStringToOString(aValueNode.getNodeName(),RTL_TEXTENCODING_ASCII_US); - OSL_ENSHURE(pValue, aStr.getStr()); - aLog.push_back(aStr); + // insert the complete subtree because it is not part of the cache yet + Subtree* pInsertInto = m_pRoot; + ConfigurationName::Iterator i = _rLocation.begin(); + while (i != _rLocation.end()) + { + // increment the iterator here, as we later may need the next position + OUString aNodeName = *i++; + Subtree* pEntry = static_cast<Subtree*>(m_pRoot->getChild(aNodeName)); + if (!pEntry) + { + Subtree* pNewChild = NULL; + if (i != _rLocation.end()) + { + // do we still have (at least) one level to go than we need a new temporary node + pNewChild = new Subtree(aNodeName); + pNewChild = static_cast<Subtree*>(pInsertInto->addChild(::std::auto_ptr<INode>(pNewChild))); + pNewChild->setLevel(0); // which means "we know nothing about any children" + } + else + { + // at this last level, we don't need an intermediate node, instead we have to insert _pSubtree here + break; + } + pEntry = pNewChild; + } + // one level down + pInsertInto = pEntry; + } + + Subtree* pNewSubtree = static_cast<Subtree*>(pInsertInto->addChild(::std::auto_ptr<INode>(_pSubtree.release()))); + pNewSubtree->setLevel(nLevels); + return pNewSubtree; } -#endif } - void TreeUpdate::handle(AddNode& aAddNode) - { - // Add a new Value - if (m_pCurrentSubtree) - m_pCurrentSubtree->addChild(aAddNode.releaseAddedNode()); -#ifdef DBUG - else - aLog.push_back(OString("TreeUpdate: no CurrentSubtree for AddNode")); -#endif - } - - void TreeUpdate::handle(RemoveNode& aRemoveNode) + std::auto_ptr<TreeChangeList> Tree::mergeSubTree(const ConfigurationName& _rLocation, std::auto_ptr<ISubtree> pSubtree) { - // remove a Value - if (m_pCurrentSubtree) - { - sal_Bool bOk = (NULL != m_pCurrentSubtree->removeChild(aRemoveNode.getNodeName()).get()); + // first look for the subtree + Subtree* pEntry = m_pRoot; + for (ConfigurationName::Iterator i = _rLocation.begin(); i != _rLocation.end() && pEntry != NULL; i++) + pEntry = static_cast<Subtree*>(pEntry->getChild(*i)); -#ifdef DBUG - ::rtl::OString aStr("TreeUpdate: Can't remove child with name:="); - aStr += rtl::OUStringToOString(aRemoveNode.getNodeName(),RTL_TEXTENCODING_ASCII_US); - OSL_ENSHURE(bOk, aStr.getStr()); - if (!bOk) - aLog.push_back(aStr); +#ifdef DEBUG + ::rtl::OString aStr("Tree: there is no Subtree for name:="); + aStr += rtl::OUStringToOString(_rLocation.fullName(), RTL_TEXTENCODING_ASCII_US); + OSL_ENSHURE(pEntry, aStr.getStr()); #endif - } - } - + if (pEntry) + { + std::auto_ptr<TreeChangeList> pChangeList(new TreeChangeList(_rLocation.getParentName().fullName(), _rLocation.localName())); + // now fill the change list + OBuildChangeTree aTreeChange(pChangeList->root, pEntry); + aTreeChange.applyToChildren(*pSubtree.get()); - void TreeUpdate::handle(SubtreeChange& aSubtree) - { - // handle traversion - ISubtree *pOldSubtree = m_pCurrentSubtree; - OSL_ENSHURE(m_pCurrentSubtree->getChild(aSubtree.getNodeName()), "TreeUpdate::handle : invalid subtree change ... this will crash !"); - m_pCurrentSubtree = m_pCurrentSubtree->getChild(aSubtree.getNodeName())->asISubtree(); + // now count if there are any changes + OChangeCounter aCounter; + pChangeList->root.dispatch(aCounter); -#if DEBUG - ::rtl::OString aStr("TreeUpdate: there is no Subtree for name:="); - aStr += rtl::OUStringToOString(aSubtree.getNodeName(),RTL_TEXTENCODING_ASCII_US); - OSL_ENSHURE(m_pCurrentSubtree, aStr.getStr()); - if (!m_pCurrentSubtree) - aLog.push_back(aStr); -#endif + if (aCounter.nCount == 0) + pChangeList.reset(); + else + { + TreeUpdate aTreeUpdate(pEntry); + pChangeList->root.forEachChange(aTreeUpdate); + } + return pChangeList; - aSubtree.forEachChange(*this); - m_pCurrentSubtree = pOldSubtree; + } + else + return std::auto_ptr<TreeChangeList>(0); } void Tree::updateTree( TreeChangeList& aTree) throw (starlang::WrappedTargetException, uno::RuntimeException) { ConfigurationName aSubtreeName(aTree.pathToRoot, aTree.root.getNodeName()); - ISubtree *pSubtree = requestSubtree(aSubtreeName.fullName(), ITreeProvider::ALL_LEVELS); + // request the subtree, atleast one level must exist! + ISubtree *pSubtree = requestSubtree(aSubtreeName.fullName(), 1); #ifdef DEBUG ::rtl::OString aStr("Tree: there is no Subtree for name:="); |