1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: treemanager.cxx,v $
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>
42 #include <osl/diagnose.h>
43 #include <rtl/logfile.hxx>
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
); }
58 // =========================================================================
60 #define MAKEUSTRING( char_array ) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( char_array ) )
61 // =========================================================================
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 // =========================================================================
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
);
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
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
)
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
);
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
);
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();
166 xBackendCache
->dispose();
170 // -------------------------------------------------------------------------
172 rtl::Reference
<CacheClientAccess
> TreeManager::getCacheAlways(RequestOptions
const & _aOptions
)
174 rtl::Reference
<CacheClientAccess
> aResult
= m_aCacheList
.get(_aOptions
);
177 rtl::Reference
<CacheClientAccess
> aNewCache( new CacheClientAccess(new ConfigChangeBroadcastHelper()) );
178 aResult
= m_aCacheList
.insert(_aOptions
,aNewCache
);
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());
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
);
241 OSL_ENSURE(aCache
.is(),"TreeManager: Cache access to fetch defaults for does not exist ! Where does the node access come from ?");
245 if (aCache
->hasModuleDefaults(aSubtreePath
))
247 CFG_TRACE_INFO_NI("TreeManager: found default data in cache");
251 configuration::AbsolutePath aRequestPath
= extractModulePath(aSubtreePath
);
253 backend::NodeRequest
aRequest(aRequestPath
,_aOptions
);
255 backend::ResultHolder
< backend::NodeInstance
> aDefaults
= getCacheLoader()->getDefaultData( aRequest
);
259 CFG_TRACE_INFO_NI("TreeManager: merging loaded defaults into cache");
260 return aCache
->insertDefaults(aDefaults
.instance());
264 CFG_TRACE_WARNING_NI("TreeManager: cannot load defaults: no data available or not supported");
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
)
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
);
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
354 aOptions
.enableAsync(false);
356 backend::UpdateRequest
anUpdate(
358 aChangeTree
.getRootNodePath(),
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());
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");
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
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
);
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
)
463 pHelper
->dispose(this);
468 // ----------------------------------------------------------------------------
469 void TreeManager::nodeUpdated(TreeChangeList
& _rChanges
)
471 CFG_TRACE_INFO("TreeManager: nodeUpdated");
474 rtl::Reference
<CacheClientAccess
> aCache
= m_aCacheList
.get(_rChanges
.getOptions());
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 // ----------------------------------------------------------------------------