diff options
Diffstat (limited to 'configmgr/source/backend/backendaccess.cxx')
-rw-r--r-- | configmgr/source/backend/backendaccess.cxx | 830 |
1 files changed, 830 insertions, 0 deletions
diff --git a/configmgr/source/backend/backendaccess.cxx b/configmgr/source/backend/backendaccess.cxx new file mode 100644 index 000000000000..6d48c1550cbd --- /dev/null +++ b/configmgr/source/backend/backendaccess.cxx @@ -0,0 +1,830 @@ +/************************************************************************* + * + * 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: backendaccess.cxx,v $ + * $Revision: 1.27 $ + * + * 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 "backendaccess.hxx" +#include "logger.hxx" +#include "matchlocale.hxx" +#include "layermerge.hxx" +#include "schemabuilder.hxx" + +#ifndef CONFIGMGR_BACKEND_UPDATEDISPATCHER_HXX +#include "updatedispatch.hxx" +#endif // CONFIGMGR_BACKEND_UPDATEDISPATCHER_HXX +#include "backendnotifier.hxx" +#include "emptylayer.hxx" +#include "filehelper.hxx" +#include "simpleinteractionrequest.hxx" +#include "configinteractionhandler.hxx" +#include <com/sun/star/configuration/backend/XVersionedSchemaSupplier.hpp> +#include <com/sun/star/configuration/backend/XCompositeLayer.hpp> +#include <com/sun/star/configuration/backend/XUpdatableLayer.hpp> +#include <com/sun/star/configuration/backend/XBackendEntities.hpp> +#include <com/sun/star/configuration/backend/MergeRecoveryRequest.hpp> +#include <com/sun/star/configuration/backend/MalformedDataException.hpp> +#include <com/sun/star/container/NoSuchElementException.hpp> +#include <com/sun/star/lang/NullPointerException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include "com/sun/star/task/XInteractionHandler.hpp" +#include <rtl/ustrbuf.hxx> +#include <rtl/ref.hxx> +#include <rtl/logfile.hxx> + +#include <cppuhelper/exc_hlp.hxx> + +#ifndef INCLUDED_VECTOR +#include <vector> +#define INCLUDED_VECTOR +#endif //INCLUDED_VECTOR + +#ifndef INCLUDED_ALGORITHM +#include <algorithm> +#define INCLUDED_ALGORITHM +#endif //INCLUDED_ALGORITHM + +#define OU2A(rtlOUString) (::rtl::OUStringToOString((rtlOUString), RTL_TEXTENCODING_ASCII_US).getStr()) +#define RTL_LOGFILE_OU2A(rtlOUString) OU2A(rtlOUString) + +#define OUSTR(txt) rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(txt) ) + +namespace configmgr { namespace backend { +//------------------------------------------------------------------------------ + namespace task = com::sun::star::task; + +inline +uno::Reference<lang::XMultiServiceFactory> BackendAccess::getServiceFactory() const +{ + return uno::Reference<lang::XMultiServiceFactory>(mContext->getServiceManager(),uno::UNO_QUERY_THROW); +} +//------------------------------------------------------------------------------ + +BackendAccess::BackendAccess( + const uno::Reference<backenduno::XBackend>& xBackend, + const uno::Reference<uno::XComponentContext>& xContext) + : mContext(xContext) + , mBackend(xBackend) + , mBinaryCache(xContext) + { + OSL_ENSURE(mContext.is(), "BackendAccess: Context is missing"); + if (!mContext.is()) + throw lang::NullPointerException(rtl::OUString::createFromAscii("BackendAccess: NULL Context passed"), NULL); + if (!xBackend.is()) + throw lang::NullPointerException(OUSTR("Configuration: Trying to create backend access without backend"),NULL); + if (!uno::Reference<backenduno::XSchemaSupplier>::query(xBackend).is()) + throw lang::NullPointerException(OUSTR("Configuration: No backend for schemas available"),NULL); + + + mNotifier = new BackendChangeNotifier(xBackend); + //Stored as uno::reference to facilitate sharing with MultiStratumBackend + mXNotifier = mNotifier; + + //Create Binary Cache + uno::Reference<backenduno::XBackendEntities> xBackendEntities = uno::Reference<backenduno::XBackendEntities>( mBackend, uno::UNO_QUERY) ; + OSL_ENSURE(xBackendEntities.is(),"Backend does not provide entity information"); + + if ( xBackendEntities.is() ) mBinaryCache.setOwnerEntity(xBackendEntities->getOwnerEntity()); +} +//------------------------------------------------------------------------------ + +BackendAccess::~BackendAccess() {} +//------------------------------------------------------------------------------ +namespace +{ +//------------------------------------------------------------------------------ + + static inline + bool findLocale(std::vector< com::sun::star::lang::Locale > const & seq, com::sun::star::lang::Locale const & loc) + { + std::vector< com::sun::star::lang::Locale >::const_iterator first = seq.begin(); + std::vector< com::sun::star::lang::Locale >::const_iterator last = seq.end(); + for ( ; first != last; ++first) + if (localehelper::equalLocale(*first, loc)) + return true; + return false; + } +//------------------------------------------------------------------------------ + + static inline + void addLocale( com::sun::star::lang::Locale const & aLocale, std::vector< com::sun::star::lang::Locale > & inoutLocales) + { + if (!findLocale(inoutLocales,aLocale)) + inoutLocales.push_back(aLocale); + } +//------------------------------------------------------------------------------ + + static rtl::OUString toString(uno::Sequence< rtl::OUString > const & seq, sal_Unicode separator = ',') + { + rtl::OUStringBuffer buf; + + if (sal_Int32 const nCount = seq.getLength()) + { + buf.append(seq[0]); + for (sal_Int32 ix=1; ix < nCount; ++ix) + buf.append(separator).append(seq[ix]); + } + else + buf.appendAscii("<none>"); + + return buf.makeStringAndClear(); + } +//------------------------------------------------------------------------------ + + static + uno::Sequence< rtl::OUString > intersect(uno::Sequence< rtl::OUString > const & seq1, uno::Sequence< rtl::OUString > const & seq2) + { + sal_Int32 const len1 = seq1.getLength(); + uno::Sequence< rtl::OUString > aResult(len1); + + rtl::OUString const * const beg2 = seq2.getConstArray(); + rtl::OUString const * const end2 = beg2 + seq2.getLength(); + + sal_Int32 ix = 0; + for (sal_Int32 i1 = 0; i1 < len1; ++i1) + { + if (std::find(beg2,end2,seq1[i1]) != end2) + aResult[ix++] = seq1[i1]; + } + aResult.realloc(ix); + return aResult; + } +//------------------------------------------------------------------------------ +} // anonymous namespace +//------------------------------------------------------------------------------ + +// helper used by the binary cache +uno::Sequence< rtl::OUString > + getAvailableLocales(const uno::Reference<backenduno::XLayer> * pLayers, sal_Int32 nNumLayers) +{ + uno::Sequence< rtl::OUString > aResult; + + for (sal_Int32 i = 0 ; i < nNumLayers ; ++ i) + { + uno::Reference<backenduno::XCompositeLayer> compositeLayer( + pLayers [i], uno::UNO_QUERY) ; + + if (compositeLayer.is()) + { + uno::Sequence<rtl::OUString> aLocales = compositeLayer->listSubLayerIds(); + + if (aResult.getLength() == 0) + { + aResult = aLocales; + } + else + { + OSL_TRACE("Warning: multiple composite layers found. Detection of available locales is inaccurate."); + // be defensive: only locales present in all composite layers are 'available' + aResult= intersect(aResult,aLocales); + } + } + } + return aResult; +} +//------------------------------------------------------------------------------ +static rtl::OUString getLayerURL(const uno::Reference<backenduno::XLayer> & aLayer); + +void BackendAccess::merge( + MergedComponentData& aData, + const uno::Reference<backenduno::XLayer> * pLayers, + sal_Int32 aNumLayers, + com::sun::star::lang::Locale const & aRequestedLocale, + std::vector< com::sun::star::lang::Locale > & inoutMergedLocales, + ITemplateDataProvider *aTemplateProvider, + sal_Int32 * pLayersMerged) + SAL_THROW((com::sun::star::uno::Exception)) +{ + LayerMergeHandler * pMerger = new LayerMergeHandler(mContext, aData, aTemplateProvider ); + uno::Reference<backenduno::XLayerHandler> xLayerMerger(pMerger); + + Logger logger(mContext); + + RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::BackendAccess", "jb99855", "configmgr: BackendAccess::merge()"); + RTL_LOGFILE_CONTEXT_TRACE1(aLog, "merging %d layers", int(aNumLayers) ); + + rtl::OUString const & aLanguage = aRequestedLocale.Language; + bool const needAllLanguages = localehelper::isAnyLanguage(aLanguage); + + if (aLanguage.getLength() && !needAllLanguages) + { + if (!localehelper::isDefaultLanguage(aLanguage)) + addLocale(aRequestedLocale,inoutMergedLocales); + } + bool const needLocalizedData = needAllLanguages || !inoutMergedLocales.empty(); + + if (logger.isLogging(LogLevel::FINEST)) + { + if (!needLocalizedData) + logger.finest("Starting merge with NO locales", "merge()","configmgr::Backend"); + + else if (needAllLanguages) + logger.finest("Starting merge for ALL locales", "merge()","configmgr::Backend"); + + else + logger.finest(OUSTR("Starting merge for locale(s): ") + + toString(localehelper::makeIsoSequence(inoutMergedLocales)), + "merge()","configmgr::Backend"); + } + + if (pLayersMerged) *pLayersMerged = 0; + + for (sal_Int32 i = 0 ; i < aNumLayers ; ++ i) + { + if (logger.isLogging(LogLevel::FINEST)) + logger.finest(OUSTR("+ Merging layer: ") + getLayerURL(pLayers[i]), + "merge()","configmgr::Backend"); + + pMerger->prepareLayer() ; + pLayers [i]->readData(xLayerMerger) ; + + if (needLocalizedData) + { + uno::Reference<backenduno::XCompositeLayer> compositeLayer( + pLayers [i], uno::UNO_QUERY) ; + + if (compositeLayer.is()) + { + uno::Sequence<rtl::OUString> aSubLayerIds = compositeLayer->listSubLayerIds(); + logger.finest(OUSTR("++ Found locales: ") + toString(aSubLayerIds), + "merge()","configmgr::Backend"); + + for (sal_Int32 j = 0; j < aSubLayerIds.getLength(); ++j) + { + rtl::OUString const & aLocaleIso = aSubLayerIds[j]; + com::sun::star::lang::Locale aLocale = localehelper::makeLocale(aLocaleIso); + + // requesting de-CH, we accept de-CH and de, but not de-DE + const localehelper::MatchQuality kMatchAccept = localehelper::MATCH_LANGUAGE_PLAIN; + + if (needAllLanguages || localehelper::isMatch(aLocale,inoutMergedLocales,kMatchAccept)) + { + if(pMerger->prepareSublayer(aLocaleIso)) + { + logger.finest(OUSTR("++ Merging sublayer for locale: ") + aLocaleIso, + "merge()","configmgr::Backend"); + compositeLayer->readSubLayerData(xLayerMerger,aLocaleIso) ; + addLocale(aLocale,inoutMergedLocales); + } + // else dropLocale(aLocale,inoutMergedLocales); ? + } + } + } + } + if (pLayersMerged) ++*pLayersMerged; + } +} +//------------------------------------------------------------------------------ + +bool BackendAccess::readDefaultData( MergedComponentData & aComponentData, + rtl::OUString const & aComponent, + RequestOptions const & aOptions, + bool bIncludeTemplates, + const uno::Reference<backenduno::XLayer> * pLayers, + sal_Int32 nNumLayers, + ITemplateDataProvider *aTemplateProvider, + sal_Int32 * pLayersMerged) + SAL_THROW((com::sun::star::uno::Exception)) +{ + RTL_LOGFILE_CONTEXT_AUTHOR(aLog1, "configmgr::backend::BackendAccess", "jb99855", "configmgr: BackendAccess::readDefaultData()"); + + Logger logger(mContext); + const sal_Int32 detail = LogLevel::FINER; + bool const bLogDetail = logger.isLogging(detail); + + rtl::OUString const aSchemaVersion = this->getSchemaVersion(aComponent); + + if (logger.isLogging(LogLevel::FINE)) + { + rtl::OUStringBuffer aMsg; + aMsg.appendAscii("Reading data for component \"").append(aComponent).appendAscii("\""); + aMsg.appendAscii(" [version=").append(aSchemaVersion).appendAscii("]"); + + logger.fine( aMsg.makeStringAndClear(), "readDefaultData()","configmgr::Backend"); + } + + com::sun::star::lang::Locale const aRequestedLocale = localehelper::makeLocale(aOptions.getLocale()); + std::vector< com::sun::star::lang::Locale > aKnownLocales; + + if (bLogDetail) logger.log(detail, "... attempt to read from binary cache", "readDefaultData()","configmgr::Backend"); + bool bCacheHit = mBinaryCache.readComponentData(aComponentData, getServiceFactory(), + aComponent, aSchemaVersion, + aOptions.getEntity(), + aRequestedLocale, aKnownLocales, + pLayers, nNumLayers, bIncludeTemplates); + + if (!bCacheHit) + { + RTL_LOGFILE_CONTEXT_AUTHOR(aLog2, "configmgr::backend::BackendAccess", "jb99855", "configmgr: BackendAccess::readDefaultData() - not in cache"); + + if (bLogDetail) logger.log(detail, "... cache miss - need full merge", "readDefaultData()","configmgr::Backend"); + if (bLogDetail) logger.log(detail, "... reading schema", "readDefaultData()","configmgr::Backend"); + { + SchemaBuilder *schemaBuilder = new SchemaBuilder( mContext, aComponent, aComponentData, aTemplateProvider ); + uno::Reference<backenduno::XSchemaHandler> schemaHandler = schemaBuilder ; + + uno::Reference<backenduno::XSchema> schema = this->getSchema(aComponent); + schema->readSchema(schemaHandler) ; + } + + if (bLogDetail) logger.log(detail, "... merging layers", "readDefaultData()","configmgr::Backend"); + this->merge(aComponentData, pLayers, nNumLayers, aRequestedLocale, aKnownLocales, aTemplateProvider, pLayersMerged ); + promoteToDefault(aComponentData); + + if (mBinaryCache.isCacheEnabled(aOptions.getEntity())) + { + if (bLogDetail) logger.log(detail, "... creating binary cache", "readDefaultData()","configmgr::Backend"); + bool bWriteSuccess = mBinaryCache.writeComponentData( aComponentData, getServiceFactory(), + aComponent, aSchemaVersion, + aOptions.getEntity(), aKnownLocales, + pLayers, nNumLayers ); + + if (!bWriteSuccess) + { + logger.info("Binary cache write failed - disabling binary cache","readDefaultData()","configmgr::Backend"); + mBinaryCache.disableCache(); + } + } + else if (bLogDetail) + logger.log(detail, "... cache hit", "readDefaultData()","configmgr::Backend"); + } + else if (pLayersMerged) + *pLayersMerged = nNumLayers; + + return aComponentData.hasSchema(); +} +//------------------------------------------------------------------------------ + +static rtl::OUString getLayerURL(const uno::Reference<backenduno::XLayer> & aLayer) +{ + try + { + namespace beans = com::sun::star::beans; + uno::Reference< beans::XPropertySet > xLayerProps( aLayer, uno::UNO_QUERY ); + if (xLayerProps.is()) + { + uno::Any aPropVal = xLayerProps->getPropertyValue( OUSTR("URL") ); + rtl::OUString aResult; + if (aPropVal >>= aResult) + return aResult; + } + OSL_TRACE("Warning - Cannot get location of layer data\n"); + } + catch (uno::Exception & e) + { + OSL_TRACE("Warning - Configuration: Retrieving layer URL failed: [%s]\n", OU2A(e.Message)); + } + // TODO: use better fallback, e.g. ServiceName + const char * const aFallback = aLayer.is() ? "<Unknown Layer Type>" : "<NULL Layer>"; + return rtl::OUString::createFromAscii(aFallback); +} +//------------------------------------------------------------------------------ +static inline +rtl::OUString getLayerIdentifier(const uno::Reference<backenduno::XLayer> & aLayer) +{ + return getLayerURL(aLayer); +} + +//------------------------------------------------------------------------------ +static void removeLayerData(uno::Reference< backenduno::XLayer > const & xLayer) +{ + OSL_ASSERT(xLayer.is()); + + uno::Reference< backenduno::XUpdatableLayer > xLayerRemover(xLayer,uno::UNO_QUERY); + if (xLayerRemover.is()) + try + { + xLayerRemover->replaceWith(createEmptyLayer()); + } + catch (uno::Exception & e) + { + OSL_TRACE("Warning - Configuration: Could not clear Layer data. Error: [%s]\n", OU2A(e.Message)); + } + else + { + if (! FileHelper::tryToRemoveFile(getLayerURL(xLayer),true)) + OSL_TRACE("Warning - Configuration: Could not remove broken user Layer data: [-Not Updatable-]\n"); + } +} +//------------------------------------------------------------------------------ + +static void discardLayer(uno::Sequence<uno::Reference<backenduno::XLayer> >& layers, sal_Int32 nLayer) +{ + OSL_ASSERT(0 <= nLayer && nLayer < layers.getLength()); + sal_Int32 nNewSize = layers.getLength() - 1; + + for (sal_Int32 i = nLayer; i<nNewSize; ++i) + layers[i] = layers[i+1]; + + layers.realloc(nNewSize); +} +//------------------------------------------------------------------------------ + +namespace { + +class RecursiveHandler: + public cppu::WeakImplHelper1< task::XInteractionHandler > +{ +public: + explicit RecursiveHandler( + uno::Reference< task::XInteractionHandler > const & outer): + m_outer(outer) {} + + virtual void SAL_CALL handle( + uno::Reference< task::XInteractionRequest > const & request) + throw (uno::RuntimeException) + { + backenduno::MergeRecoveryRequest req; + if (request->getRequest() >>= req) { + uno::Sequence< uno::Reference< task::XInteractionContinuation > > + cs(request->getContinuations()); + for (sal_Int32 i = 0; i < cs.getLength(); ++i) { + uno::Reference< task::XInteractionDisapprove > dis( + cs[i], uno::UNO_QUERY); + if (dis.is()) { + dis->select(); + break; + } + } + } else if (m_outer.is()) { + m_outer->handle(request); + } + } + +private: + RecursiveHandler(RecursiveHandler &); // not defined + void operator =(RecursiveHandler &); // not defined + + virtual ~RecursiveHandler() {} + + uno::Reference< task::XInteractionHandler > m_outer; +}; + +} + +bool BackendAccess::approveRecovery(const uno::Any & aMergeException, + const uno::Reference<backenduno::XLayer> & aBrokenLayer, + bool bUserLayerData) + SAL_THROW((com::sun::star::uno::Exception)) +{ + sal_uInt32 const k_supported_choices = apihelper::CONTINUATION_APPROVE | apihelper::CONTINUATION_DISAPPROVE; + + sal_uInt32 chosen = apihelper::CONTINUATION_UNKNOWN; + + apihelper::ConfigurationInteractionHandler handler; + try { + uno::Reference< task::XInteractionHandler > h(handler.get()); + if (h.is()) { + handler.setRecursive(new RecursiveHandler(h)); + rtl::Reference< apihelper::SimpleInteractionRequest > req( + new apihelper::SimpleInteractionRequest( + uno::makeAny( + backenduno::MergeRecoveryRequest( + rtl::OUString( + RTL_CONSTASCII_USTRINGPARAM( + "Recover from configuration merge" + " failure")), + aBrokenLayer, aMergeException, + getLayerIdentifier(aBrokenLayer), + (bUserLayerData + && (uno::Reference< backenduno::XUpdatableLayer >::query(aBrokenLayer).is() + || FileHelper::fileExists( + getLayerURL(aBrokenLayer)))))), + k_supported_choices)); + h->handle(req.get()); + chosen = req->getResponse(); + } + } catch (uno::Exception & e) { + OSL_TRACE("Warning - Configuration: Interaction handler failed: [%s]\n", OU2A(e.Message)); + } + + switch (chosen) + { + case apihelper::CONTINUATION_APPROVE: return true; + case apihelper::CONTINUATION_DISAPPROVE: return false; + case apihelper::CONTINUATION_UNKNOWN: break; + + default: OSL_ENSURE(false,"Unsolicited continuation chosen"); break; + } + // no choice available - default: approve, if user data + return bUserLayerData; +} +//------------------------------------------------------------------------------ + +ResultHolder< ComponentInstance > BackendAccess::getNodeData(const ComponentRequest& aRequest, + ITemplateDataProvider *_aTemplateProvider, + INodeDataListener *aListener) + SAL_THROW((com::sun::star::uno::Exception)) +{ + rtl::OUString const component = aRequest.getComponentName(); + ITemplateDataProvider * const aTemplateProvider = _aTemplateProvider ? _aTemplateProvider : this; + + RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::BackendAccess", "jb99855", "configmgr: BackendAccess::getNodeData()"); + RTL_LOGFILE_CONTEXT_TRACE1(aLog, "request path: %s", RTL_LOGFILE_OU2A(component) ); + + uno::Sequence<uno::Reference<backenduno::XLayer> > layers = + this->getLayers(component, aRequest.getOptions()) ; + + sal_Int32 const k_NumUserLayers = 1; + + sal_Int32 nNumDefaultLayers = layers.getLength() - k_NumUserLayers; + sal_Int32 nCurrentLayer( -1 ); + bool bDefaultRecoveryApproved = false; + + Logger logger(mContext); + do try // loop to allow recovery from merge failures + { + MergedComponentData aComponentData; + nCurrentLayer = -1; + + if (!this->readDefaultData(aComponentData, component, aRequest.getOptions(), true, + layers.getConstArray(),nNumDefaultLayers, + aTemplateProvider, &nCurrentLayer)) + { + rtl::OUStringBuffer sMessage; + sMessage.appendAscii("Configuration: No data for request. Component \""); + sMessage.append(component); + sMessage.appendAscii("\" contains no data. "); + + throw com::sun::star::container::NoSuchElementException(sMessage.makeStringAndClear(),mBackend); + } + OSL_ASSERT(nCurrentLayer == nNumDefaultLayers); + + sal_Int32 const nNumUserLayers = layers.getLength() - nNumDefaultLayers; + if (nNumUserLayers > 0) + { + //Merge User layer (with all locales) + logger.finer("... merging user layer", "getNodeData()","configmgr::Backend"); + + std::vector< com::sun::star::lang::Locale > aLocales; + merge(aComponentData, + layers.getConstArray()+nNumDefaultLayers, nNumUserLayers, + localehelper::getAnyLocale(), aLocales, aTemplateProvider ); + + // mark this one as done + ++nCurrentLayer; + } + + logger.finer("Reading component data finished successfully", "getNodeData()","configmgr::Backend"); + + ComponentInstance retCode(aComponentData.extractSchemaTree(), + aComponentData.extractTemplatesTree(), + aRequest.getComponentName()) ; + + //Register listener with notifier + if(aListener) + { + mNotifier->addListener(aListener, aRequest); + } + return ResultHolder< ComponentInstance >(retCode) ; + } + catch (com::sun::star::container::NoSuchElementException &) { throw; } + catch (com::sun::star::uno::RuntimeException &) { throw; } + catch (uno::Exception & ) + { + // can only recover if layer merging broke + if (nCurrentLayer < 0 || layers.getLength() <= nCurrentLayer) + throw; + + uno::Reference< backenduno::XLayer > xBrokenLayer = layers[nCurrentLayer]; + + bool bUserLayerBroken = (nCurrentLayer == nNumDefaultLayers); + + if (!bDefaultRecoveryApproved || bUserLayerBroken) + { + logger.info("Parsing data layer failed. Requesting approval for automated recovery", "getNodeData()","configmgr::Backend"); + uno::Any theError = cppu::getCaughtException(); + if (!approveRecovery(theError,xBrokenLayer,bUserLayerBroken)) + cppu::throwException( theError ); + } + + // now do the recovery + discardLayer(layers,nCurrentLayer); + if (bUserLayerBroken) + { + logger.info("Recovering from broken user data layer - discarding the data", "getNodeData()","configmgr::Backend"); + removeLayerData(xBrokenLayer); + } + else + { + logger.info("Recovering from broken default layer - skipping", "getNodeData()","configmgr::Backend"); + bDefaultRecoveryApproved = true; + --nNumDefaultLayers; + } + } + while (true); +} +//------------------------------------------------------------------------------ + +void BackendAccess::updateNodeData(const UpdateRequest& aUpdate) + SAL_THROW((com::sun::star::uno::Exception)) +{ + rtl::OUString entity = aUpdate.getOptions().getEntity() ; + rtl::OUString component = + aUpdate.getUpdateRoot().getModuleName(); + uno::Reference<backenduno::XUpdateHandler> handler ; + + RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::BackendAccess", "jb99855", "configmgr: BackendAccess::updateNodeData()"); + RTL_LOGFILE_CONTEXT_TRACE1(aLog, "updating component: %s", RTL_LOGFILE_OU2A(component) ); + + if (entity.getLength() == 0) { + handler = mBackend->getOwnUpdateHandler(component) ; + } + else { handler = mBackend->getUpdateHandler(component, entity) ; } + UpdateDispatcher dispatcher(handler, aUpdate.getOptions().getLocale()) ; + + dispatcher.dispatchUpdate(aUpdate.getUpdateRoot(), + *aUpdate.getUpdateData()) ; +} +//------------------------------------------------------------------------------ + +ResultHolder< NodeInstance > BackendAccess::getDefaultData(const NodeRequest& aRequest) + SAL_THROW((com::sun::star::uno::Exception)) +{ + rtl::OUString const component = aRequest.getPath().getModuleName(); + + RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::BackendAccess", "jb99855", "configmgr: BackendAccess::getDefaultData()"); + RTL_LOGFILE_CONTEXT_TRACE1(aLog, "request path: %s", RTL_LOGFILE_OU2A(aRequest.getPath().toString()) ); + + uno::Sequence<uno::Reference<backenduno::XLayer> > const layers = + this->getLayers(component, aRequest.getOptions()) ; + + sal_Int32 const nNumUserLayers = 1; + sal_Int32 const nNumDefaultLayers = layers.getLength() - nNumUserLayers; + + MergedComponentData aComponentData; + + if (!this->readDefaultData(aComponentData, component, aRequest.getOptions(), false, + layers.getConstArray(),nNumDefaultLayers, + this)) + { + rtl::OUStringBuffer sMessage; + sMessage.appendAscii("Configuration: No data for request. Component \""); + sMessage.append(component); + sMessage.appendAscii("\" contains no default data. "); + + rtl::OUString const sMsg = sMessage.makeStringAndClear(); + Logger(mContext).finer(sMsg,"getDefaultData()","configmgr::BackendAccess"); + throw com::sun::star::container::NoSuchElementException(sMsg,mBackend); + } + + std::auto_ptr<ISubtree> aResultTree = aComponentData.extractSchemaTree(); + + configuration::AbsolutePath aPath = aRequest.getPath(); + if( aPath.begin() != aPath.end()) + { + for(std::vector<configuration::Path::Component>::const_reverse_iterator it=aPath.begin()+1,endIt=aPath.end();it!=endIt; ++it) + { + std::auto_ptr<INode> aChild=aResultTree->removeChild(it->getName()); + if(aChild.get()== NULL) + { + rtl::OUStringBuffer sMessage; + sMessage.appendAscii("Configuration: No data for request. Element \""); + sMessage.append(aPath.toString()); + sMessage.appendAscii("\" does not exist in the default data. "); + + rtl::OUString const sMsg = sMessage.makeStringAndClear(); + Logger(mContext).finest(sMsg,"getDefaultData()","configmgr::BackendAccess"); + throw com::sun::star::container::NoSuchElementException(sMsg,mBackend); + } + + ISubtree *pChildAsSubtree = aChild->asISubtree(); + if(pChildAsSubtree == NULL) + { + rtl::OUString sMsg = rtl::OUString::createFromAscii("BackendAccess::getDefaultData - Node Expected, Found Property: ").concat(it->getName()); + Logger(mContext).finer(sMsg,"getDefaultData()","configmgr::BackendAccess"); + throw backenduno::MalformedDataException(sMsg, mBackend, uno::Any()); + } + aResultTree.reset(pChildAsSubtree); + aChild.release(); + } + } + + NodeInstance retCode(aResultTree, aRequest.getPath()) ; + return ResultHolder< NodeInstance >(retCode) ; +} +//------------------------------------------------------------------------------ + +ResultHolder< TemplateInstance > BackendAccess::getTemplateData(const TemplateRequest& aRequest) + SAL_THROW((com::sun::star::uno::Exception)) +{ + rtl::OUString component = aRequest.getComponentName(); + + RTL_LOGFILE_CONTEXT_AUTHOR(aLog, "configmgr::backend::BackendAccess", "jb99855", "configmgr: BackendAccess::getTemplateData()"); + RTL_LOGFILE_CONTEXT_TRACE2(aLog, "requested template: %s/%s", + RTL_LOGFILE_OU2A(aRequest.getComponentName().toString()) , + aRequest.isComponentRequest() ? "*" : RTL_LOGFILE_OU2A(aRequest.getComponentName().toString()) ); + + MergedComponentData aComponentData; + + { + SchemaBuilder *schemaBuilder = new SchemaBuilder( mContext, component, aComponentData ) ; + uno::Reference<backenduno::XSchemaHandler> handler = schemaBuilder ; + + uno::Reference<backenduno::XSchema> schema = this->getSchema(component); + + schema->readTemplates(handler) ; + } + + TemplateInstance::Data aResultData; + if (aRequest.isComponentRequest()) + { + aResultData.reset( aComponentData.extractTemplatesTree().release() ); + } + else + { + backenduno::TemplateIdentifier templateId ; + templateId.Name = aRequest.getTemplateName(); + templateId.Component = aRequest.getComponentName(); + + aResultData = aComponentData.extractTemplateNode(templateId.Name); + } + + TemplateInstance retCode(aResultData,aRequest.getTemplateName(), aRequest.getComponentName()) ; + return ResultHolder< TemplateInstance >(retCode) ; +} +//------------------------------------------------------------------------------ + +uno::Reference< backenduno::XSchema > BackendAccess::getSchema(const rtl::OUString& aComponent) +{ + uno::Reference< backenduno::XSchemaSupplier > xSchemaBackend(mBackend, uno::UNO_QUERY_THROW); + OSL_ASSERT(xSchemaBackend.is()); + + uno::Reference< backenduno::XSchema > xSchema = xSchemaBackend->getComponentSchema(aComponent) ; + if (!xSchema.is()) + { + rtl::OUStringBuffer sMessage; + sMessage.appendAscii("Configuration: No data for request. Component \""); + sMessage.append(aComponent); + sMessage.appendAscii("\" is unknown. [No schema available]"); + + rtl::OUString const sMsg = sMessage.makeStringAndClear(); + Logger(mContext).warning(sMsg,"getSchema()","configmgr::BackendAccess"); + throw com::sun::star::container::NoSuchElementException(sMsg,xSchemaBackend); + } + + return xSchema; +} +//------------------------------------------------------------------------------ + +rtl::OUString BackendAccess::getSchemaVersion(const rtl::OUString& aComponent) +{ + uno::Reference< backenduno::XVersionedSchemaSupplier > xSchemaBackend(mBackend, uno::UNO_QUERY); + if (xSchemaBackend.is()) + return xSchemaBackend->getSchemaVersion(aComponent); + else + return rtl::OUString(); +} +//------------------------------------------------------------------------------ + +uno::Sequence< uno::Reference<backenduno::XLayer> > BackendAccess::getLayers(const rtl::OUString& aComponent,const RequestOptions& aOptions) +{ + rtl::OUString aEntity = aOptions.getEntity() ; + + if (aEntity.getLength() == 0) + { + // Use own entity instead + return mBackend->listOwnLayers(aComponent) ; + } + else + { + return mBackend->listLayers(aComponent, aEntity) ; + } +} +//------------------------------------------------------------------------------ +void BackendAccess::removeRequestListener(INodeDataListener *aListener, + const ComponentRequest& aRequest) + SAL_THROW(()) +{ + + OSL_PRECOND(aListener, "ERROR: trying to remove a NULL listener"); + mNotifier->removeListener(aListener, aRequest); +} +//------------------------------------------------------------------------------ +} } // configmgr.backend |