update dev300-m58
[ooovba.git] / configmgr / source / treecache / treemanager.cxx
blob44b36bf53a7ccdf772ff4d6bb7f2caa00a497001
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: treemanager.cxx,v $
10 * $Revision: 1.14 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
34 #include "treemanager.hxx"
35 #include "mergeddataprovider.hxx"
36 #include "cacheaccess.hxx"
37 #include "cachecontroller.hxx"
38 #include "cachemulticaster.hxx"
39 #include <com/sun/star/container/NoSuchElementException.hpp>
40 #include <com/sun/star/lang/DisposedException.hpp>
41 #include "tracer.hxx"
42 #include <osl/diagnose.h>
43 #include <rtl/logfile.hxx>
45 namespace configmgr
48 namespace uno = ::com::sun::star::uno;
49 namespace lang= ::com::sun::star::lang;
51 namespace Path = configuration::Path;
52 // =========================================================================
53 //#if OSL_DEBUG_LEVEL > 0
54 #if 0 // currently not used in debug build!
55 static void test_complete(memory::HeapManager & _rDummy)
56 { new TreeManager(NULL,_rDummy); }
57 #endif
58 // =========================================================================
60 #define MAKEUSTRING( char_array ) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( char_array ) )
61 // =========================================================================
63 static inline
64 configuration::AbsolutePath extractModulePath(configuration::AbsolutePath const & _aPath)
66 if (_aPath.getDepth() <= 1) return _aPath;
68 rtl::OUString aModule = _aPath.getModuleName();
70 return configuration::AbsolutePath::makeModulePath(aModule);
72 // =========================================================================
74 // disposing
75 // -------------------------------------------------------------------------
76 void TreeManager::disposeAll()
78 CFG_TRACE_INFO("TreeManager: Disposing all data" );
79 CacheList::Map aReleaseList;
81 m_aCacheList.swap(aReleaseList); // move data out of m_aCacheList
83 // free all the trees - not exception safe !! (i.e. disposeBroadcastHelper() must not throw)
84 for (CacheList::Map::iterator i = aReleaseList.begin(); i != aReleaseList.end(); ++i)
86 if (ConfigChangeBroadcastHelper * pHelper = i->second->releaseBroadcaster())
87 disposeBroadcastHelper(pHelper);
88 i->second.clear();
92 // -------------------------------------------------------------------------
93 void TreeManager::dispose()
95 CFG_TRACE_INFO("TreeManager: dispoing the treemanager" );
97 RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::TreeManager", "jb99855", "configmgr: TreeManager::dispose().");
99 rtl::Reference< backend::CacheController > xBackendCache = maybeGetBackendCache();
101 if (xBackendCache.is()) xBackendCache->getNotifier().removeListener(this);
103 // cleaning the cache
104 disposeAll();
106 disposeBackendCache();
109 // -------------------------------------------------------------------------
110 ConfigChangeBroadcastHelper* TreeManager::getBroadcastHelper(RequestOptions const& _aOptions, bool bCreate)
112 rtl::Reference<CacheClientAccess> aCache = bCreate ? this->getCacheAlways(_aOptions)
113 : m_aCacheList.get(_aOptions);
115 return aCache.is() ? aCache->getBroadcaster() : NULL;
119 // -------------------------------------------------------------------------
120 TreeManager::TreeManager(rtl::Reference< backend::CacheController > const & _xBackend)
121 : m_xCacheController(_xBackend)
122 , m_aCacheList()
123 , m_aTemplates(new CacheData())
124 , m_bEnableAsync(true)
126 OSL_PRECOND(_xBackend.is(),"Trying to create a TreeManager without a backend");
128 if (m_xCacheController.is()) m_xCacheController->getNotifier().addListener(this);
131 // -------------------------------------------------------------------------
132 TreeManager::~TreeManager()
136 // -------------------------------------------------------------------------
137 rtl::Reference< backend::CacheController > TreeManager::maybeGetBackendCache() SAL_THROW(())
139 osl::MutexGuard aGuard(m_aCacheControllerMutex);
140 rtl::Reference< backend::CacheController > xResult(m_xCacheController);
141 return xResult;
144 // -------------------------------------------------------------------------
145 rtl::Reference< backend::CacheController > TreeManager::getCacheLoader() SAL_THROW((com::sun::star::uno::RuntimeException))
147 osl::MutexGuard aGuard(m_aCacheControllerMutex);
148 if (!m_xCacheController.is())
150 rtl::OUString sMsg = rtl::OUString::createFromAscii("TreeManager: No backend available - tree manager was already disposed.");
151 throw com::sun::star::lang::DisposedException(sMsg,NULL);
153 rtl::Reference< backend::CacheController > xResult(m_xCacheController);
154 return xResult;
157 // -------------------------------------------------------------------------
158 void TreeManager::disposeBackendCache() SAL_THROW(())
160 osl::ClearableMutexGuard aGuard(m_aCacheControllerMutex);
161 if (m_xCacheController.is())
163 rtl::Reference< backend::CacheController > xBackendCache(m_xCacheController);
164 m_xCacheController.clear();
165 aGuard.clear();
166 xBackendCache->dispose();
170 // -------------------------------------------------------------------------
172 rtl::Reference<CacheClientAccess> TreeManager::getCacheAlways(RequestOptions const & _aOptions)
174 rtl::Reference<CacheClientAccess> aResult = m_aCacheList.get(_aOptions);
175 if (!aResult.is())
177 rtl::Reference<CacheClientAccess> aNewCache( new CacheClientAccess(new ConfigChangeBroadcastHelper()) );
178 aResult = m_aCacheList.insert(_aOptions,aNewCache);
180 return aResult;
183 // -------------------------------------------------------------------------
185 sharable::Node * TreeManager::requestSubtree(configuration::AbsolutePath const& aSubtreePath,
186 const RequestOptions& _aOptions)
187 SAL_THROW((com::sun::star::uno::Exception))
189 CFG_TRACE_INFO("TreeManager: request for subtree '%s'", OUSTRING2ASCII(aSubtreePath.toString()));
191 rtl::Reference<CacheClientAccess> aCache = getCacheAlways(_aOptions);
192 OSL_ENSURE(aCache.is(),"TreeManager: Cannot create cache access for loading node");
194 if (!aCache->hasModule(aSubtreePath))
196 CFG_TRACE_INFO_NI("TreeManager: cache miss. going to load the node");
197 backend::ComponentRequest aQuery( aSubtreePath.getModuleName(), _aOptions );
199 sharable::TreeFragment * aLoadedLocation = getCacheLoader()->loadComponent(aQuery);
200 if (aLoadedLocation == NULL)
202 CFG_TRACE_WARNING_NI("TreeManager: requested component not found");
203 throw com::sun::star::container::
204 NoSuchElementException( MAKEUSTRING("Requested component not found"), NULL);
207 CFG_TRACE_INFO_NI("TreeManager: attaching loaded cache segment ");
208 aCache->attachModule(aLoadedLocation,aSubtreePath.getModuleName());
210 else
212 CFG_TRACE_INFO_NI("TreeManager: found node in cache");
213 if (_aOptions.isRefreshEnabled())
215 backend::ComponentRequest aRequest( aSubtreePath.getModuleName(), _aOptions );
216 getCacheLoader()->refreshComponent(aRequest);
220 return aCache->acquireNode(aSubtreePath);
223 // -------------------------------------------------------------------------
224 void TreeManager::fetchSubtree(configuration::AbsolutePath const& aSubtreePath, const RequestOptions& ) SAL_THROW(())
226 (void) aSubtreePath; // avoid warning about unused parameter
227 CFG_TRACE_WARNING("TreeManager: Prefetching not implemented. (Request to prefetch component %s.", OUSTRING2ASCII(aSubtreePath.toString()));
230 // -------------------------------------------------------------------------
231 sal_Bool TreeManager::fetchDefaultData( configuration::AbsolutePath const& aSubtreePath,
232 const RequestOptions& _aOptions
233 ) SAL_THROW((com::sun::star::uno::Exception))
235 CFG_TRACE_INFO("tree manager: checking the cache for defaults");
237 rtl::Reference<CacheClientAccess> aCache = m_aCacheList.get(_aOptions);
239 if (!aCache.is())
241 OSL_ENSURE(aCache.is(),"TreeManager: Cache access to fetch defaults for does not exist ! Where does the node access come from ?");
242 return false;
245 if (aCache->hasModuleDefaults(aSubtreePath))
247 CFG_TRACE_INFO_NI("TreeManager: found default data in cache");
248 return true;
251 configuration::AbsolutePath aRequestPath = extractModulePath(aSubtreePath);
253 backend::NodeRequest aRequest(aRequestPath,_aOptions);
255 backend::ResultHolder< backend::NodeInstance > aDefaults = getCacheLoader()->getDefaultData( aRequest );
257 if (!aDefaults.is())
259 CFG_TRACE_INFO_NI("TreeManager: merging loaded defaults into cache");
260 return aCache->insertDefaults(aDefaults.instance());
262 else
264 CFG_TRACE_WARNING_NI("TreeManager: cannot load defaults: no data available or not supported");
265 return false;
269 // -------------------------------------------------------------------------
270 std::auto_ptr<ISubtree> TreeManager::requestDefaultData(configuration::AbsolutePath const& aSubtreePath,
271 const RequestOptions& _aOptions
272 ) SAL_THROW((com::sun::star::uno::Exception))
274 // to do: check cache for existing default data (?!)
275 CFG_TRACE_INFO_NI("TreeManager: loading default data directly");
277 backend::NodeRequest aRequest(aSubtreePath,_aOptions);
279 backend::ResultHolder< backend::NodeInstance > aDefaults = getCacheLoader()->getDefaultData( aRequest );
281 return aDefaults.extractDataAndClear();
284 // -------------------------------------------------------------------------
285 configuration::AbsolutePath TreeManager::encodeTemplateLocation(const rtl::OUString& _rLogicalTemplateName, const rtl::OUString &_rModule)
287 // static const
288 // configuration::Path::Component aTemplateRoot = configuration::Path::wrapSimpleName(rtl::OUString::createFromAscii("org.openoffice.Templates"));
290 configuration::Path::Component aTemplateModule = configuration::Path::wrapSimpleName(_rModule);
291 configuration::Path::Component aTemplateName = configuration::Path::wrapSimpleName(_rLogicalTemplateName);
293 Path::Rep aResult(aTemplateName);
294 aResult.prepend(aTemplateModule);
295 // aResult.prepend(aTemplateRoot);
297 return configuration::AbsolutePath(aResult);
300 // -------------------------------------------------------------------------
301 sharable::TreeFragment * TreeManager::requestTemplate(rtl::OUString const& _rName,
302 rtl::OUString const& _rModule) SAL_THROW((com::sun::star::uno::Exception))
304 OSL_ENSURE(_rName.getLength() != 0, "TreeManager::requestTemplate : invalid template name !");
306 CFG_TRACE_INFO("TreeManager: going to get a template named %s", OUSTRING2ASCII(_rName));
308 configuration::AbsolutePath aTemplateLocation = encodeTemplateLocation(_rName, _rModule);
309 rtl::OUString aCacheModule = aTemplateLocation.getModuleName();
311 if (!getTemplates().hasNode(aTemplateLocation))
313 CFG_TRACE_INFO_NI("TreeManager: cache miss. going to load the template");
314 backend::TemplateRequest aQuery( _rName, _rModule );
316 sharable::TreeFragment * aLoadedLocation = getCacheLoader()->loadTemplate(aQuery);
317 if (aLoadedLocation == NULL)
319 CFG_TRACE_ERROR_NI("TreeManager: requested template module not found");
320 throw com::sun::star::container::
321 NoSuchElementException( MAKEUSTRING("Requested template module not found"), NULL);
324 CFG_TRACE_INFO_NI("TreeManager: attaching to loaded template module");
326 getTemplates().attachModule(aLoadedLocation,aCacheModule);
328 // create a client ref count on the template module
329 getTemplates().acquireNode(aTemplateLocation);
331 else
333 CFG_TRACE_INFO_NI("TreeManager: template module found in cache");
336 sharable::TreeFragment * aTemplateAddr = getTemplates().getTemplateTree(aTemplateLocation);
337 if (aTemplateAddr == NULL)
339 CFG_TRACE_ERROR_NI("TreeManager: template not found in module");
340 throw com::sun::star::container::
341 NoSuchElementException( MAKEUSTRING("Unknown template. Type description could not be found in the given module."), NULL);
343 return aTemplateAddr;
346 // -------------------------------------------------------------------------
347 void TreeManager::saveAndNotifyUpdate(TreeChangeList const& aChangeTree) SAL_THROW((com::sun::star::uno::Exception))
350 CFG_TRACE_INFO("TreeManager: committing an Update to the cache controller");
351 RequestOptions aOptions = aChangeTree.getOptions();;
352 //Modify RequestOptions - suppress async commit, if disabled
353 if(!m_bEnableAsync)
354 aOptions.enableAsync(false);
356 backend::UpdateRequest anUpdate(
357 & aChangeTree.root,
358 aChangeTree.getRootNodePath(),
359 aOptions);
361 getCacheLoader()->saveAndNotify(anUpdate);
362 CFG_TRACE_INFO_NI("TreeManager: committing done");
366 // -----------------------------------------------------------------------------
367 void TreeManager::updateTree(TreeChangeList& _aChanges) SAL_THROW((com::sun::star::uno::Exception))
369 CFG_TRACE_INFO("TreeManager: updating the cache from a changes list");
371 backend::UpdateInstance anUpdate(&_aChanges.root,_aChanges.getRootNodePath());
373 rtl::Reference<CacheClientAccess> aCache = m_aCacheList.get(_aChanges.getOptions());
375 if (!aCache.is())
377 CFG_TRACE_ERROR_NI("TreeManager: Cache access to update into does not exist !");
378 OSL_ENSURE(aCache.is(),"TreeManager: Cache access to update into does not exist ! Where does the update access come from ?");
379 throw lang::DisposedException(rtl::OUString::createFromAscii("Tree to be updated was already disposed"), NULL);
382 // merge the changes into the tree
383 aCache->applyUpdate(anUpdate);
385 CFG_TRACE_INFO_NI("TreeManager: cache update done");
388 // -----------------------------------------------------------------------------
390 //-----------------------------------------------------------------------------
391 void TreeManager::releaseSubtree( configuration::AbsolutePath const& aSubtreePath, const RequestOptions& _aOptions ) SAL_THROW(())
393 CFG_TRACE_INFO("TreeManager: releasing subtree '%s' for entity '%s' with locale '%s'", OUSTRING2ASCII(aSubtreePath.toString()), OUSTRING2ASCII(_aOptions.getEntity()), OUSTRING2ASCII(_aOptions.getLocale()) );
395 rtl::Reference<CacheClientAccess> aCache = m_aCacheList.get(_aOptions);
397 OSL_ENSURE(aCache.is(),"TreeManager: No local data to release");
399 if (aCache.is())
401 CFG_TRACE_INFO_NI("TreeManager: decrementing refcount for subtree '%s'", OUSTRING2ASCII(aSubtreePath.toString()) );
402 if (aCache->releaseNode(aSubtreePath) == 0)
404 backend::ComponentRequest aComponentDesc(aSubtreePath.getModuleName(),_aOptions);
405 rtl::Reference< backend::CacheController > xBackendCache = maybeGetBackendCache();
406 if (xBackendCache.is()) xBackendCache->freeComponent(aComponentDesc);
410 // ----------------------------------------------------------------------------
411 void TreeManager::refreshAll() SAL_THROW((com::sun::star::uno::Exception))
413 //Find what components are in cache and that have client references and reload
414 //such components.
415 rtl::Reference< backend::CacheController > aCacheRef = maybeGetBackendCache();
416 if (aCacheRef.is()) aCacheRef->refreshAllComponents();
418 // ----------------------------------------------------------------------------
419 void TreeManager::flushAll()SAL_THROW(())
421 rtl::Reference< backend::CacheController > aCacheRef = maybeGetBackendCache();
422 if (aCacheRef.is()) aCacheRef->flushPendingUpdates();
424 //-----------------------------------------------------------------------------
425 void TreeManager::enableAsync(const sal_Bool& bEnableAsync) SAL_THROW(())
427 m_bEnableAsync = bEnableAsync;
430 /////////////////////////////////////////////////////////////////////////
431 void TreeManager::addListener(configuration::AbsolutePath const& aName, RequestOptions const & _aOptions, rtl::Reference<INodeListener> const& pHandler)
433 if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(_aOptions,true))
435 pHelper->addListener(aName, pHandler);
437 else
438 OSL_ASSERT(false);
441 void TreeManager::removeListener(RequestOptions const & _aOptions, rtl::Reference<INodeListener> const& pHandler)
443 if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(_aOptions,false))
445 pHelper->removeListener( pHandler);
449 /////////////////////////////////////////////////////////////////////////
450 void TreeManager::fireChanges(TreeChangeList const& rList_, sal_Bool bError_)
452 if (ConfigChangeBroadcastHelper* pHelper = getBroadcastHelper(rList_.getOptions(),false))
454 pHelper->broadcast(rList_, bError_, this);
458 /////////////////////////////////////////////////////////////////////////
459 void TreeManager::disposeBroadcastHelper(ConfigChangeBroadcastHelper* pHelper)
461 if (pHelper)
463 pHelper->dispose(this);
464 delete pHelper;
468 // ----------------------------------------------------------------------------
469 void TreeManager::nodeUpdated(TreeChangeList& _rChanges)
471 CFG_TRACE_INFO("TreeManager: nodeUpdated");
474 rtl::Reference<CacheClientAccess> aCache = m_aCacheList.get(_rChanges.getOptions());
476 if (aCache.is())
478 // first approve the changes and merge them with the current tree
479 configuration::AbsolutePath aSubtreeName = _rChanges.getRootNodePath();
481 sharable::Node * aCacheTree = aCache->findInnerNode(aSubtreeName);
482 //OSL_ENSURE(aCacheTree != NULL, "TreeManager::nodeUpdated : node not found in cache!");
484 if (aCacheTree != NULL)
485 this->fireChanges(_rChanges,false);
488 catch (uno::RuntimeException&)
490 CFG_TRACE_ERROR_NI("TreeManager::nodeUpdated : could not notify !");
492 CFG_TRACE_INFO_NI("TreeManager: nodeUpdated done");
495 // ----------------------------------------------------------------------------
497 void TreeManager::componentCreated(backend::ComponentRequest const & ) SAL_THROW(())
499 CFG_TRACE_INFO("TreeManager: component was created");
501 // ----------------------------------------------------------------------------
503 void TreeManager::componentChanged(backend::UpdateRequest const & _anUpdate) SAL_THROW(())
505 TreeChangeList aChanges(_anUpdate.getOptions(),
506 _anUpdate.getUpdateRoot(),
507 *_anUpdate.getUpdateData(),
508 treeop::DeepChildCopy() );
510 this->nodeUpdated(aChanges);
512 // ----------------------------------------------------------------------------
514 // ----------------------------------------------------------------------------
515 } // namespace