426c368530
2008/04/01 15:06:54 thb 1.19.16.3: #i85898# Stripping all external header guards 2008/04/01 12:27:34 thb 1.19.16.2: #i85898# Stripping all external header guards 2008/03/31 12:22:53 rt 1.19.16.1: #i87441# Change license header to LPGL v3.
860 lines
32 KiB
C++
860 lines
32 KiB
C++
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2008 by Sun Microsystems, Inc.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: cachecontroller.cxx,v $
|
|
* $Revision: 1.20 $
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org 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 version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_configmgr.hxx"
|
|
|
|
#include "cachecontroller.hxx"
|
|
#include "disposetimer.hxx"
|
|
#include "cachewritescheduler.hxx"
|
|
#include "treeaccessor.hxx"
|
|
#include "builddata.hxx"
|
|
#include "localizedtreeactions.hxx"
|
|
#include "configexcept.hxx"
|
|
#include "tracer.hxx"
|
|
#include <com/sun/star/lang/DisposedException.hpp>
|
|
#include <com/sun/star/container/NoSuchElementException.hpp>
|
|
#include <osl/diagnose.h>
|
|
#include <rtl/logfile.hxx>
|
|
|
|
#ifndef _CONFIGMGR_BOOTSTRAP_HXX
|
|
#include "bootstrap.hxx"
|
|
#endif
|
|
|
|
|
|
#define RTL_LOGFILE_OU2A(rtlOUString) (::rtl::OUStringToOString((rtlOUString), RTL_TEXTENCODING_ASCII_US).getStr())
|
|
|
|
namespace configmgr
|
|
{
|
|
// -------------------------------------------------------------------------
|
|
namespace backend
|
|
{
|
|
|
|
static const rtl::OUString kCacheDisposeDelay(
|
|
RTL_CONSTASCII_USTRINGPARAM( CONTEXT_ITEM_PREFIX_ "CacheDisposeDelay"));
|
|
static const rtl::OUString kCacheDisposeInterval(
|
|
RTL_CONSTASCII_USTRINGPARAM( CONTEXT_ITEM_PREFIX_ "CacheDisposeInterval"));
|
|
static const rtl::OUString kCacheWriteInterval(
|
|
RTL_CONSTASCII_USTRINGPARAM( CONTEXT_ITEM_PREFIX_ "CacheWriteInterval"));
|
|
// -------------------------------------------------------------------------
|
|
|
|
OTreeDisposeScheduler* CacheController::createDisposer(const CreationContext& _xContext)
|
|
{
|
|
ContextReader aReader(_xContext);
|
|
sal_uInt32 c_nDefaultDelay = 0;
|
|
OUString sDefaultDelay;
|
|
aReader.getBestContext()->getValueByName(kCacheDisposeDelay) >>= sDefaultDelay;
|
|
c_nDefaultDelay = sDefaultDelay.toInt32()==0?900:sDefaultDelay.toInt32() ;
|
|
|
|
sal_uInt32 c_nDefaultInterval = 0;
|
|
OUString sDefaultInterval;
|
|
aReader.getBestContext()->getValueByName(kCacheDisposeInterval) >>= sDefaultInterval;
|
|
c_nDefaultInterval = sDefaultInterval.toInt32()==0?60:sDefaultInterval.toInt32();
|
|
|
|
TimeInterval aDelay(c_nDefaultDelay);
|
|
TimeInterval aInterval(c_nDefaultInterval);
|
|
|
|
return new OTreeDisposeScheduler(*this, aDelay, aInterval);
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
OCacheWriteScheduler* CacheController::createCacheWriter(const CreationContext& _xContext)
|
|
{
|
|
ContextReader aReader(_xContext);
|
|
sal_uInt32 c_nDefaultInterval=0;
|
|
OUString sDefaultInterval;
|
|
aReader.getBestContext()->getValueByName(kCacheWriteInterval) >>= sDefaultInterval;
|
|
c_nDefaultInterval = sDefaultInterval.toInt32()==0?2:sDefaultInterval.toInt32();
|
|
|
|
TimeInterval aInterval(c_nDefaultInterval);
|
|
return new OCacheWriteScheduler(*this, aInterval);
|
|
}
|
|
// ----------------------------------------------------------------------------
|
|
|
|
CacheController::CacheRef CacheController::getCacheAlways(RequestOptions const & _aOptions)
|
|
{
|
|
CacheRef aResult = m_aCacheMap.get(_aOptions);
|
|
if (!aResult.is())
|
|
{
|
|
CacheRef aNewCache( new Cache() );
|
|
aResult = m_aCacheMap.insert(_aOptions,aNewCache);
|
|
}
|
|
return aResult;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// disposing
|
|
// -------------------------------------------------------------------------
|
|
void CacheController::disposeAll(bool _bFlushRemainingUpdates)
|
|
{
|
|
CFG_TRACE_INFO("CacheController: Disposing all data" );
|
|
CacheMap::Map aReleaseList;
|
|
|
|
if (m_pDisposer)
|
|
{
|
|
m_pDisposer->stopAndClearTasks();
|
|
m_aCacheMap.swap(aReleaseList); // move data out of m_aCacheMap and empty m_aCacheMap
|
|
}
|
|
|
|
if (_bFlushRemainingUpdates)
|
|
{
|
|
for (CacheMap::Map::iterator it = aReleaseList.begin(); it != aReleaseList.end(); ++it)
|
|
saveAllPendingChanges(it->second,it->first);
|
|
}
|
|
// free all the trees
|
|
aReleaseList.clear();
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
void CacheController::dispose() CFG_UNO_THROW_RTE()
|
|
{
|
|
UnoApiLock aLock;
|
|
|
|
CFG_TRACE_INFO("CacheController: dispose()" );
|
|
|
|
RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::CacheController", "jb99855", "configmgr: CacheController::dispose(), disable lazy write cache.");
|
|
m_bDisposing = true; // we are in dispose, handling of errors must be something different.
|
|
|
|
// writing of pending updates
|
|
this->flushCacheWriter();
|
|
|
|
// cleaning the cache
|
|
this->disposeAll(true);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
void CacheController::disposeOne(RequestOptions const & _aOptions, bool _bFlushUpdates)
|
|
{
|
|
CFG_TRACE_INFO("CacheController: Disposing data and TreeInfo for user '%s' with locale '%s'",
|
|
OUSTRING2ASCII(_aOptions.getEntity()), OUSTRING2ASCII(_aOptions.getLocale()) );
|
|
|
|
m_pDisposer->clearTasks(_aOptions);
|
|
if (!m_pCacheWriter->clearTasks(_aOptions)) // had no pending updates
|
|
{
|
|
_bFlushUpdates = false;
|
|
}
|
|
else if (!_bFlushUpdates)
|
|
{
|
|
CFG_TRACE_WARNING_NI("Found orphaned Changes in the cache - Discarding.");
|
|
}
|
|
|
|
CacheRef aRemoved = m_aCacheMap.remove(_aOptions);
|
|
|
|
if (aRemoved.is())
|
|
{
|
|
// got it out of reachability - now dispose/notify without lock
|
|
implDisposeOne(aRemoved, _aOptions, _bFlushUpdates);
|
|
}
|
|
else
|
|
CFG_TRACE_INFO_NI("- No affected TreeInfo found" );
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
void CacheController::disposeUser(RequestOptions const & _aUserOptions, bool _bFlushUpdates)
|
|
{
|
|
CFG_TRACE_INFO("CacheController: Disposing data and TreeInfo(s) for user '%s'",
|
|
OUSTRING2ASCII(_aUserOptions.getEntity()) );
|
|
|
|
typedef std::vector< std::pair< RequestOptions, CacheRef > > DisposeList;
|
|
|
|
DisposeList aDisposeList;
|
|
// collect the ones to dispose
|
|
{
|
|
OUString sUser = _aUserOptions.getEntity();
|
|
OSL_ASSERT(sUser.getLength());
|
|
|
|
// This depends on the fact that Options are sorted (by struct ltOptions)
|
|
// so that all options belonging to one user are together
|
|
// (and that options with only a user set, sort first)
|
|
|
|
CacheMap::Map aCacheData;
|
|
m_aCacheMap.swap(aCacheData);
|
|
|
|
// find the lower_bound of all options for the user
|
|
CacheMap::Map::iterator const aFirst = aCacheData.lower_bound(_aUserOptions);
|
|
|
|
// find the upper_bound of all options for the user (using the lower one)
|
|
CacheMap::Map::iterator aLast = aFirst;
|
|
while (aLast != aCacheData.end() && aLast->first.getEntity() == sUser)
|
|
++aLast;
|
|
|
|
if (aFirst != aLast)
|
|
{
|
|
aDisposeList.reserve( std::distance(aFirst, aLast) );
|
|
|
|
bool bHasPendingChanges = false;
|
|
|
|
for (CacheMap::Map::iterator it = aFirst; it != aLast; ++it)
|
|
{
|
|
CFG_TRACE_INFO_NI("- Found TreeInfo for locale '%s'", OUSTRING2ASCII(it->first.getLocale()) );
|
|
m_pDisposer->clearTasks(it->first);
|
|
|
|
if (m_pCacheWriter->clearTasks(it->first))
|
|
bHasPendingChanges = true;
|
|
|
|
OSL_ASSERT(it->second.is());
|
|
if (it->second.is())
|
|
{
|
|
//aDisposeList.push_back( *it );
|
|
aDisposeList.push_back( std::make_pair(it->first,it->second) );
|
|
}
|
|
}
|
|
|
|
if (!bHasPendingChanges)
|
|
_bFlushUpdates = false;
|
|
|
|
else if (!_bFlushUpdates)
|
|
CFG_TRACE_WARNING_NI("Found orphaned Changes in the cache - Discarding.");
|
|
|
|
aCacheData.erase(aFirst, aLast);
|
|
}
|
|
else
|
|
CFG_TRACE_INFO_NI("- No affected TreeInfo found" );
|
|
|
|
// replace the data into the map
|
|
m_aCacheMap.swap(aCacheData);
|
|
}
|
|
|
|
// got all out of external reach - now dispose/notify without lock
|
|
for (DisposeList::iterator i = aDisposeList.begin(); i != aDisposeList.end(); ++i)
|
|
{
|
|
if (i->second.is())
|
|
implDisposeOne(i->second, i->first, _bFlushUpdates);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
void CacheController::implDisposeOne(CacheRef const & _aDisposedCache, RequestOptions const & _aOptions, bool _bFlushUpdates)
|
|
{
|
|
OSL_ASSERT(_aDisposedCache.is());
|
|
CFG_TRACE_INFO("Now removing Cache section (user '%s' with locale '%s')",
|
|
OUSTRING2ASCII(_aOptions.getEntity()), OUSTRING2ASCII(_aOptions.getLocale()) );
|
|
|
|
if (_bFlushUpdates) try
|
|
{
|
|
CFG_TRACE_INFO_NI("- Flushing pending changes" );
|
|
|
|
if ( !this->saveAllPendingChanges(_aDisposedCache,_aOptions) )
|
|
{
|
|
CFG_TRACE_ERROR_NI("- Error while flushing - changes will be lost" );
|
|
OSL_ENSURE(false,"Error while flushing changes from discarded Cache section - changes will be lost" );
|
|
}
|
|
}
|
|
catch (uno::Exception& e)
|
|
{
|
|
(void)e;
|
|
CFG_TRACE_ERROR_NI("- Failed with exception %s (ignoring here)", OUSTRING2ASCII(e.Message) );
|
|
}
|
|
|
|
Cache::DisposeList aDisposedList;
|
|
_aDisposedCache->clearData(aDisposedList);
|
|
|
|
if (aDisposedList.size() > 0)
|
|
{
|
|
CFG_TRACE_INFO_NI("- Closing %d modules at the session",int(aDisposedList.size()));
|
|
this->closeModules(aDisposedList,_aOptions);
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
CacheController::CacheController(BackendRef const & _xBackend,
|
|
const uno::Reference<uno::XComponentContext>& xContext)
|
|
: m_aNotifier()
|
|
, m_xBackend(_xBackend)
|
|
, m_aCacheMap()
|
|
, m_aTemplates()
|
|
, m_pDisposer()
|
|
, m_pCacheWriter()
|
|
, m_bDisposing(false)
|
|
{
|
|
m_pDisposer = this->createDisposer(xContext);
|
|
m_pCacheWriter = this->createCacheWriter(xContext);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
CacheController::~CacheController()
|
|
{
|
|
OSL_ENSURE(m_bDisposing == true, "CacheController::dispose() wasn't called, something went wrong.");
|
|
|
|
delete m_pDisposer;
|
|
delete m_pCacheWriter;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
void CacheController::closeModules(Cache::DisposeList & _aList, RequestOptions const & _aOptions)
|
|
{
|
|
//Remove listeners from Backend as module no longer in cache
|
|
for (sal_uInt32 i =0; i < _aList.size(); ++i)
|
|
{
|
|
Name aModuleName = _aList[i]->getModuleName();
|
|
ComponentRequest aRequest(aModuleName, _aOptions);
|
|
m_xBackend->removeRequestListener(this, aRequest);
|
|
}
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
#if 0
|
|
static
|
|
std::auto_ptr<ISubtree> reduceSubtreeForLocale(std::auto_ptr<ISubtree> _pSubtree, RequestOptions const & _aOptions)
|
|
{
|
|
OSL_ENSURE(!_pSubtree.get() || !isLocalizedValueSet(*_pSubtree), "Unexpected node. Expecting a subtree, Found a single localized value.");
|
|
|
|
std::auto_ptr<ISubtree> aRet;
|
|
|
|
std::auto_ptr<INode> aReduced = reduceExpandedForLocale(_pSubtree, _aOptions.getLocale());
|
|
|
|
if (aReduced.get())
|
|
{
|
|
if (ISubtree* pReduced =aReduced->asISubtree())
|
|
{
|
|
aRet.reset(pReduced);
|
|
aReduced.release();
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE(false, "Tree unexpectedly reduced to non-tree");
|
|
}
|
|
}
|
|
else
|
|
OSL_ENSURE(!_pSubtree.get(), "Tree unexpectedly reduced to nothing");
|
|
|
|
return aRet;
|
|
}
|
|
#endif
|
|
|
|
// -------------------------------------------------------------------------
|
|
CacheLocation CacheController::loadComponent(ComponentRequest const & _aRequest)
|
|
{
|
|
CFG_TRACE_INFO("CacheController: loading component '%s'", OUSTRING2ASCII(_aRequest.getComponentName().toString()));
|
|
|
|
RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::CacheController", "jb99855", "configmgr: CacheController::loadComponent()");
|
|
RTL_LOGFILE_CONTEXT_TRACE1(aLog, "component: %s", RTL_LOGFILE_OU2A(_aRequest.getComponentName().toString()) );
|
|
|
|
CacheRef aCache = this->getCacheAlways(_aRequest.getOptions());
|
|
|
|
OSL_ENSURE(aCache.is(), "Could not create CacheAccess");
|
|
|
|
data::TreeAddress aTemplateResultAdddress;
|
|
|
|
OSL_ENSURE(!_aRequest.isForcingReload(),"CacheController: No support for forced requests");
|
|
if (aCache->hasModule(_aRequest.getComponentName()))
|
|
{
|
|
CFG_TRACE_INFO_NI("CacheController: found node in cache");
|
|
if (_aRequest.getOptions().isRefreshEnabled())
|
|
{
|
|
refreshComponent(_aRequest);
|
|
}
|
|
aCache->acquireModule(_aRequest.getComponentName());
|
|
}
|
|
else
|
|
{
|
|
ComponentResult aData = this->loadDirectly(_aRequest,true);
|
|
|
|
bool bWithDefaults = ! m_xBackend->isStrippingDefaults();
|
|
|
|
CFG_TRACE_INFO_NI("CacheController: adding loaded data to the cache");
|
|
|
|
aCache->createModule(_aRequest.getComponentName());
|
|
|
|
aCache->addComponentData(aData.instance(), bWithDefaults);
|
|
if (aData.instance().templateData().get()!=NULL)
|
|
aTemplateResultAdddress = addTemplates(aData.mutableInstance().componentTemplateData() );
|
|
|
|
// notify the new data to all clients
|
|
m_aNotifier.notifyCreated(_aRequest);
|
|
}
|
|
|
|
return aCache->getTreeAddress(_aRequest.getComponentName());
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
|
|
ComponentResult CacheController::getComponentData(ComponentRequest const & _aRequest,
|
|
bool _bAddListenter ) CFG_UNO_THROW_ALL()
|
|
{
|
|
// TODO: Insert check here, if the data is in the cache already - and then clone
|
|
RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::CacheController", "jb99855", "configmgr: CacheController::getComponentData()");
|
|
RTL_LOGFILE_CONTEXT_TRACE1(aLog, "component: %s", RTL_LOGFILE_OU2A(_aRequest.getComponentName().toString()) );
|
|
|
|
ComponentResult aRet = this->loadDirectly(_aRequest, _bAddListenter);
|
|
|
|
return aRet;
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
|
|
NodeResult CacheController::getDefaultData(NodeRequest const & _aRequest) CFG_UNO_THROW_ALL( )
|
|
{
|
|
// TODO: Insert check here, if the data is in the cache already - and then clone
|
|
RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::CacheController", "jb99855", "configmgr: CacheController::getDefaultData()");
|
|
RTL_LOGFILE_CONTEXT_TRACE1(aLog, "path: %s", RTL_LOGFILE_OU2A(_aRequest.getPath().toString()) );
|
|
|
|
NodeResult aRet = this->loadDefaultsDirectly(_aRequest);
|
|
|
|
return aRet;
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
|
|
AbsolutePath CacheController::encodeTemplateLocation(const Name& _rName, const Name &_rModule) const
|
|
{
|
|
namespace Path = configuration::Path;
|
|
|
|
// static const
|
|
// Component aTemplateRoot = wrapSimpleName(OUString::createFromAscii("org.openoffice.Templates"));
|
|
|
|
Path::Component aTemplateModule = Path::wrapSimpleName(_rModule);
|
|
Path::Component aTemplateName = Path::wrapSimpleName(_rName);
|
|
|
|
Path::Rep aResult(aTemplateName);
|
|
aResult.prepend(aTemplateModule);
|
|
// aResult.prepend(aTemplateRoot);
|
|
|
|
return AbsolutePath(aResult);
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
#if 0
|
|
static
|
|
AbsolutePath templateLoadLocation(const AbsolutePath &_rTemplateLocation)
|
|
{
|
|
namespace Path = configuration::Path;
|
|
|
|
static const
|
|
Path::Component aTemplateRoot = Path::wrapSimpleName(OUString::createFromAscii("org.openoffice.Templates"));
|
|
|
|
Path::Rep aResult(_rTemplateLocation.rep());
|
|
aResult.prepend(aTemplateRoot);
|
|
|
|
return AbsolutePath(aResult);
|
|
}
|
|
#endif
|
|
// -------------------------------------------------------------------------
|
|
std::auto_ptr<ISubtree> CacheController::loadTemplateData(TemplateRequest const & _aTemplateRequest) CFG_UNO_THROW_ALL( )
|
|
{
|
|
std::auto_ptr<ISubtree> aMultiTemplates;
|
|
TemplateResult aTemplateInstance = m_xBackend->getTemplateData(_aTemplateRequest);
|
|
if (aTemplateInstance.is())
|
|
{
|
|
OSL_ASSERT(aTemplateInstance->name().isEmpty());
|
|
if (ISubtree * pMulti = aTemplateInstance->data()->asISubtree())
|
|
{
|
|
aTemplateInstance.releaseAndClear();
|
|
aMultiTemplates.reset(pMulti);
|
|
}
|
|
else
|
|
OSL_ENSURE(false,"Requested multiple templates, got non-subtree node");
|
|
}
|
|
else
|
|
OSL_ENSURE(false,"Requested configuration template does not exist");
|
|
|
|
if (aMultiTemplates.get() == NULL)
|
|
{
|
|
CFG_TRACE_ERROR_NI("CacheController: could not load the templates");
|
|
throw uno::Exception(::rtl::OUString::createFromAscii("The template description could not be loaded. The template does not exist."), NULL);
|
|
}
|
|
|
|
return aMultiTemplates;
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
data::TreeAddress CacheController::addTemplates ( backend::ComponentData const & _aComponentInstance )
|
|
{
|
|
OSL_PRECOND(_aComponentInstance.data.get(), "addTemplates: Data must not be NULL");
|
|
CacheLine::Name aModuleName = _aComponentInstance.name;
|
|
m_aTemplates.createModule(aModuleName);
|
|
AbsolutePath aTemplateLocation = AbsolutePath::makeModulePath(_aComponentInstance.name , AbsolutePath::NoValidate());
|
|
data::TreeAddress aTemplateAddr = NULL;
|
|
|
|
if (!m_aTemplates.hasNode(aTemplateLocation ))
|
|
{
|
|
CFG_TRACE_INFO_NI("CacheController: cache miss for that template - loading from backend");
|
|
aTemplateAddr = m_aTemplates.addTemplates(_aComponentInstance );
|
|
}
|
|
OSL_ASSERT (aTemplateAddr != NULL);
|
|
return aTemplateAddr;
|
|
}
|
|
// -------------------------------------------------------------------------
|
|
|
|
CacheLocation CacheController::loadTemplate(TemplateRequest const & _aRequest) CFG_UNO_THROW_ALL( )
|
|
{
|
|
|
|
OSL_ENSURE(!_aRequest.getTemplateName().isEmpty(), "CacheController::loadTemplate : invalid template name !");
|
|
RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::CacheController", "jb99855", "configmgr: CacheController::loadTemplate()");
|
|
RTL_LOGFILE_CONTEXT_TRACE2(aLog, "requested template: %s/%s",
|
|
RTL_LOGFILE_OU2A(_aRequest.getComponentName().toString()) ,
|
|
_aRequest.isComponentRequest() ?
|
|
"*" : RTL_LOGFILE_OU2A(_aRequest.getComponentName().toString()) );
|
|
|
|
|
|
AbsolutePath aTemplateLocation = encodeTemplateLocation(_aRequest.getTemplateName(), _aRequest.getComponentName());
|
|
|
|
CacheLine::Name aModuleName = aTemplateLocation.getModuleName();
|
|
|
|
AbsolutePath aTemplateParent (aTemplateLocation.getParentPath());
|
|
|
|
//Load-if-not-there (componentwise)
|
|
if (!m_aTemplates.hasNode(aTemplateParent))
|
|
{
|
|
OSL_ENSURE(aTemplateLocation.getDepth() > 1, "CacheController::ensureTemplate : invalid template location !");
|
|
TemplateRequest aTemplateRequest = TemplateRequest::forComponent(_aRequest.getComponentName());
|
|
|
|
std::auto_ptr<ISubtree> aMultiTemplates = loadTemplateData(aTemplateRequest);
|
|
//add-if-not-loaded
|
|
addTemplates(backend::ComponentData(aMultiTemplates, aModuleName));
|
|
|
|
}
|
|
data::TreeAddress aTemplateAddr = m_aTemplates.getTemplateTree(aTemplateLocation);
|
|
if (aTemplateAddr == NULL)
|
|
throw uno::Exception(::rtl::OUString::createFromAscii("Unknown template. Type description could not be found in the given module."), NULL);
|
|
|
|
return m_aTemplates.getTreeAddress(aTemplateLocation.getModuleName());
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
TemplateResult CacheController::getTemplateData(TemplateRequest const & _aRequest)
|
|
CFG_UNO_THROW_ALL()
|
|
{
|
|
RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::CacheController", "jb99855", "configmgr: CacheController::getTemplateData()");
|
|
RTL_LOGFILE_CONTEXT_TRACE2(aLog, "requested template: %s/%s",
|
|
RTL_LOGFILE_OU2A(_aRequest.getComponentName().toString()) ,
|
|
_aRequest.isComponentRequest() ?
|
|
"*" : RTL_LOGFILE_OU2A(_aRequest.getComponentName().toString()) );
|
|
|
|
AbsolutePath aTemplateLocation = encodeTemplateLocation(_aRequest.getTemplateName(), _aRequest.getComponentName());
|
|
|
|
loadTemplate(_aRequest);
|
|
//AbsolutePath aTemplateLocation = ensureTemplate(_aRequest.getTemplateName(), _aRequest.getComponentName());
|
|
|
|
data::TreeAddress aTemplateAddr = m_aTemplates.getTemplateTree(aTemplateLocation);
|
|
if (aTemplateAddr == NULL)
|
|
throw uno::Exception(::rtl::OUString::createFromAscii("Unknown template. Type description could not be found in the given module."), NULL);
|
|
|
|
data::TreeAccessor aTemplateTree(aTemplateAddr);
|
|
|
|
std::auto_ptr<INode> aResultTree = data::convertTree(aTemplateTree, true);
|
|
|
|
TemplateInstance aResult(aResultTree,_aRequest.getTemplateName(), _aRequest.getComponentName());
|
|
|
|
return TemplateResult(aResult);
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void CacheController::saveAndNotify(UpdateRequest const & _anUpdate) CFG_UNO_THROW_ALL( )
|
|
{
|
|
RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::CacheController", "jb99855", "configmgr: CacheController::saveAndNotify()");
|
|
RTL_LOGFILE_CONTEXT_TRACE1(aLog, "location: %s", RTL_LOGFILE_OU2A(_anUpdate.getUpdateRoot().toString()) );
|
|
try
|
|
{
|
|
// ---------- preworking on the changes ----------
|
|
// caller must own a read lock on this cache line
|
|
CFG_TRACE_INFO("CacheController: saving an update for '%s'",OUSTRING2ASCII(_anUpdate.getUpdateRoot().toString()));
|
|
|
|
CacheRef aCache = m_aCacheMap.get(_anUpdate.getOptions());
|
|
|
|
OSL_ENSURE(aCache.is(), "No cache data to update in saveAndNotify");
|
|
|
|
if (!aCache.is()) throw lang::DisposedException(OUString::createFromAscii("Tree to be updated was already disposed"), NULL);
|
|
|
|
aCache->addChangesToPending(_anUpdate.getUpdate());
|
|
|
|
if ( _anUpdate.isSyncRequired()|| m_bDisposing ) // cannot do it asynchronously
|
|
{
|
|
CFG_TRACE_INFO_NI("Running synchronous write");
|
|
savePendingChanges( aCache, getComponentRequest(_anUpdate) );
|
|
}
|
|
|
|
else
|
|
{
|
|
CFG_TRACE_INFO_NI("Posting asynchronous write");
|
|
m_pCacheWriter->scheduleWrite( getComponentRequest(_anUpdate) );
|
|
}
|
|
|
|
CFG_TRACE_INFO_NI("Notifying the changes");
|
|
// notify the changes to all clients
|
|
m_aNotifier.notifyChanged(_anUpdate);
|
|
}
|
|
catch(configuration::Exception& ex)
|
|
{
|
|
CFG_TRACE_ERROR_NI("Got unexpected exception: %s", ex.what());
|
|
configapi::ExceptionMapper e(ex);
|
|
e.unhandled();
|
|
}
|
|
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void CacheController::flushPendingUpdates()CFG_UNO_THROW_ALL()
|
|
{
|
|
CacheMap::Map aFlushList = m_aCacheMap.copy();
|
|
|
|
for (CacheMap::Map::iterator it = aFlushList.begin(); it != aFlushList.end(); ++it)
|
|
saveAllPendingChanges(it->second,it->first);
|
|
}
|
|
|
|
void CacheController::flushCacheWriter()CFG_NOTHROW()
|
|
{
|
|
//OSL_ASSERT(m_bDisposing);
|
|
|
|
if (m_pCacheWriter)
|
|
{
|
|
CFG_TRACE_INFO("CacheController: flushing all pending updates");
|
|
|
|
m_pCacheWriter->stopAndWriteCache();
|
|
}
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
bool CacheController::normalizeResult(std::auto_ptr<ISubtree> & _aResult, RequestOptions const & _aOptions)
|
|
{
|
|
|
|
if (_aResult.get()==NULL) return false;
|
|
|
|
if (_aOptions.isForAllLocales()) return true;
|
|
|
|
std::auto_ptr<INode> aReduced = reduceExpandedForLocale(_aResult, _aOptions.getLocale());
|
|
|
|
std::auto_ptr<ISubtree> aReducedTree;
|
|
if (aReduced.get())
|
|
{
|
|
if (ISubtree* pReducedTree =aReduced->asISubtree())
|
|
{
|
|
aReduced.release();
|
|
aReducedTree.reset(pReducedTree);
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE(false, "Tree unexpectedly reduced to non-tree");
|
|
}
|
|
}
|
|
else
|
|
OSL_ENSURE(false, "Tree unexpectedly reduced to nothing");
|
|
|
|
|
|
_aResult = aReducedTree;
|
|
bool retCode = _aResult.get()!=NULL ? true : false;
|
|
return retCode;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
ComponentResult CacheController::loadDirectly(ComponentRequest const & _aRequest, bool _bAddListenter) CFG_UNO_THROW_ALL( )
|
|
{
|
|
CFG_TRACE_INFO("CacheController: loading data for component '%s' from the backend", OUSTRING2ASCII(_aRequest.getComponentName().toString()));
|
|
|
|
AbsolutePath aRequestPath = AbsolutePath::makeModulePath(_aRequest.getComponentName(), AbsolutePath::NoValidate());
|
|
|
|
NodeRequest aNodeRequest(aRequestPath, _aRequest.getOptions());
|
|
|
|
ComponentResult aResult = m_xBackend->getNodeData(_aRequest, this, _bAddListenter?this:NULL);
|
|
|
|
OSL_PRECOND(aResult.mutableInstance().mutableData().get(), "loadDirectly: Data must not be NULL");
|
|
|
|
CFG_TRACE_INFO_NI("- loading data completed - normalizing result");
|
|
|
|
if (!normalizeResult( aResult.mutableInstance().mutableData(),_aRequest.getOptions()))
|
|
{
|
|
CFG_TRACE_ERROR_NI(" - cannot normalized result: failing");
|
|
|
|
OUString sMsg(RTL_CONSTASCII_USTRINGPARAM("Requested data at '"));
|
|
sMsg += aRequestPath.toString();
|
|
sMsg += OUString(RTL_CONSTASCII_USTRINGPARAM("'is not available: "));
|
|
|
|
throw com::sun::star::container::NoSuchElementException(sMsg,NULL);
|
|
}
|
|
|
|
CFG_TRACE_INFO_NI(" - returning normalized defaults");
|
|
|
|
return aResult;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
NodeResult CacheController::loadDefaultsDirectly(NodeRequest const & _aRequest) CFG_UNO_THROW_ALL( )
|
|
{
|
|
CFG_TRACE_INFO("CacheController: loading defaults for '%s' from the backend", OUSTRING2ASCII(_aRequest.getPath().toString()));
|
|
|
|
NodeResult aResult = m_xBackend->getDefaultData(_aRequest);
|
|
|
|
CFG_TRACE_INFO_NI("- loading defaultscompleted - normalizing result");
|
|
|
|
normalizeResult(aResult.mutableInstance().mutableData(),_aRequest.getOptions());
|
|
|
|
CFG_TRACE_INFO_NI(" - returning normalized defaults");
|
|
|
|
return aResult;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void CacheController::saveDirectly(UpdateRequest const & _anUpdate) CFG_UNO_THROW_ALL( )
|
|
{
|
|
m_xBackend->updateNodeData(_anUpdate);
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
void CacheController::savePendingChanges(CacheRef const & _aCache, ComponentRequest const & _aComponent) CFG_UNO_THROW_ALL( )
|
|
{
|
|
CFG_TRACE_INFO("CacheController: saving updates for tree: '%s'", OUSTRING2ASCII(_aComponent.getComponentName().toString()));
|
|
|
|
try
|
|
{
|
|
CFG_TRACE_INFO2("CacheController: saving updates for tree: '%s'", OUSTRING2ASCII(_aComponent.getComponentName().toString()));
|
|
|
|
std::auto_ptr<SubtreeChange> aChangeData = _aCache->releasePendingChanges(_aComponent.getComponentName());
|
|
|
|
if (aChangeData.get())
|
|
{
|
|
CFG_TRACE_INFO_NI("- found changes - sending to backend");
|
|
|
|
AbsolutePath aRootPath = AbsolutePath::makeModulePath(_aComponent.getComponentName(), AbsolutePath::NoValidate());
|
|
|
|
backend::UpdateRequest anUpdateSpec(aChangeData.get(),aRootPath,_aComponent.getOptions());
|
|
|
|
// anUpdateSpec.setRequestId(pInfo->getRequestId(_aRootPath));
|
|
|
|
this->saveDirectly(anUpdateSpec);
|
|
|
|
CFG_TRACE_INFO_NI("- saving changes completed successfully");
|
|
}
|
|
else
|
|
CFG_TRACE_WARNING_NI("- no changes found - cannot save");
|
|
}
|
|
catch(uno::Exception& e)
|
|
{
|
|
(void)e;
|
|
CFG_TRACE_ERROR_NI("CacheController: saving tree '%s' failed: %s",
|
|
OUSTRING2ASCII(_aComponent.getComponentName().toString()),
|
|
OUSTRING2ASCII(e.Message) );
|
|
|
|
this->invalidateComponent(_aComponent);
|
|
CFG_TRACE_INFO_NI("- component data invalidated");
|
|
|
|
throw;
|
|
}
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
bool CacheController::saveAllPendingChanges(CacheRef const & _aCache, RequestOptions const & _aOptions)
|
|
CFG_UNO_THROW_RTE( )
|
|
{
|
|
CFG_TRACE_INFO("CacheController: Saving all pending changes for cache line");
|
|
OSL_ASSERT(_aCache.is());
|
|
|
|
typedef ExtendedCacheData::PendingModuleList PMList;
|
|
|
|
PMList aPendingModules;
|
|
_aCache->findPendingChangedModules(aPendingModules);
|
|
|
|
CFG_TRACE_INFO_NI("Found %d changed modules",int(aPendingModules.size()));
|
|
|
|
bool bSuccess = true;
|
|
for (PMList::iterator it = aPendingModules.begin();
|
|
it != aPendingModules.end();
|
|
++it )
|
|
{
|
|
try
|
|
{
|
|
this->savePendingChanges(_aCache, ComponentRequest(*it,_aOptions) );
|
|
}
|
|
catch (uno::Exception & )
|
|
{
|
|
CFG_TRACE_ERROR_NI("CacheController: Exception while saving one module - ignoring");
|
|
bSuccess = false;
|
|
}
|
|
}
|
|
CFG_TRACE_INFO_NI("Done saving pending changes for cache line");
|
|
|
|
return bSuccess;
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void CacheController::freeComponent(ComponentRequest const & _aRequest) CFG_NOTHROW()
|
|
{
|
|
CFG_TRACE_INFO("CacheController: releasing module '%s' for user '%s' with locale '%s'",
|
|
OUSTRING2ASCII(_aRequest.getComponentName().toString()),
|
|
OUSTRING2ASCII(_aRequest.getOptions().getEntity()),
|
|
OUSTRING2ASCII(_aRequest.getOptions().getLocale()) );
|
|
|
|
CacheRef aCache = m_aCacheMap.get(_aRequest.getOptions());
|
|
|
|
OSL_ENSURE(aCache.is(), "Releasing a nonexisting module");
|
|
|
|
if (aCache.is())
|
|
{
|
|
if (aCache->releaseModule(_aRequest.getComponentName()) == 0)
|
|
{
|
|
// start the cleanup
|
|
m_pDisposer->scheduleCleanup(_aRequest.getOptions());
|
|
}
|
|
}
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
void CacheController::dataChanged(const ComponentRequest& _aRequest) CFG_NOTHROW()
|
|
{
|
|
refreshComponent(_aRequest);
|
|
}
|
|
// -----------------------------------------------------------------------------
|
|
void CacheController::refreshAllComponents() CFG_UNO_THROW_ALL()
|
|
{
|
|
CacheMap::Map aRefreshList = m_aCacheMap.copy();
|
|
|
|
for (CacheMap::Map::iterator i = aRefreshList.begin();
|
|
i != aRefreshList.end(); ++i)
|
|
{
|
|
if (!i->second->isEmpty())
|
|
{
|
|
ExtendedCacheData aCacheData = i->second->m_aData;
|
|
RequestOptions aOption = i->first;
|
|
CacheData::ModuleList aModuleList = aCacheData.accessModuleList();
|
|
for (CacheData::ModuleList::iterator itr = aModuleList.begin();
|
|
itr != aModuleList.end(); ++itr)
|
|
{
|
|
//Check the cacheline has atleast one client reference
|
|
|
|
|
|
if (itr->second->clientReferences() > 0)
|
|
{
|
|
ComponentRequest aRequest(itr->first,i->first);
|
|
refreshComponent(aRequest);
|
|
} else
|
|
{
|
|
// FIXME: otherwise dispose now
|
|
// XXX: (lo) refresh all, preventing cache corruption.
|
|
// An unused component should be purged from the cache
|
|
// instead of being refreshed
|
|
ComponentRequest aRequest(itr->first,i->first);
|
|
refreshComponent(aRequest);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// -------------------------------------------------------------------------
|
|
} // namespace
|
|
|
|
// -------------------------------------------------------------------------
|
|
} // namespace
|