/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dp_compbackenddb.hxx" using namespace ::dp_misc; using namespace ::com::sun::star; using namespace ::com::sun::star::uno; using namespace ::com::sun::star::ucb; namespace dp_registry::backend::component { namespace { /** return a vector of bootstrap variables which have been provided as command arguments. */ std::vector getCmdBootstrapVariables() { std::vector ret; sal_uInt32 count = osl_getCommandArgCount(); for (sal_uInt32 i = 0; i < count; i++) { OUString arg; osl_getCommandArg(i, &arg.pData); if (arg.startsWith("-env:")) ret.push_back(arg); } return ret; } bool jarManifestHeaderPresent( OUString const & url, OUString const & name, Reference const & xCmdEnv ) { OUStringBuffer buf; buf.append( "vnd.sun.star.zip://" ); buf.append( ::rtl::Uri::encode( url, rtl_UriCharClassRegName, rtl_UriEncodeIgnoreEscapes, RTL_TEXTENCODING_UTF8 ) ); buf.append( "/META-INF/MANIFEST.MF" ); ::ucbhelper::Content manifestContent; OUString line; return create_ucb_content( &manifestContent, buf.makeStringAndClear(), xCmdEnv, false /* no throw */ ) && readLine( &line, name, manifestContent, RTL_TEXTENCODING_ASCII_US ); } class BackendImpl : public ::dp_registry::backend::PackageRegistryBackend { class ComponentPackageImpl : public ::dp_registry::backend::Package { BackendImpl * getMyBackend() const; const OUString m_loader; enum class Reg { Uninit, Void, Registered, NotRegistered, MaybeRegistered }; Reg m_registered; void getComponentInfo( ComponentBackendDb::Data * data, std::vector< css::uno::Reference< css::uno::XInterface > > * factories, Reference const & xContext ); void componentLiveInsertion( ComponentBackendDb::Data const & data, std::vector< css::uno::Reference< css::uno::XInterface > > const & factories); void componentLiveRemoval(ComponentBackendDb::Data const & data); // Package virtual beans::Optional< beans::Ambiguous > isRegistered_( ::osl::ResettableMutexGuard & guard, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) override; virtual void processPackage_( ::osl::ResettableMutexGuard & guard, bool registerPackage, bool startup, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) override; Reference getRDB() const; public: ComponentPackageImpl( ::rtl::Reference const & myBackend, OUString const & url, OUString const & name, Reference const & xPackageType, OUString const & loader, bool bRemoved, OUString const & identifier); }; friend class ComponentPackageImpl; class ComponentsPackageImpl : public ::dp_registry::backend::Package { BackendImpl * getMyBackend() const; // Package virtual beans::Optional< beans::Ambiguous > isRegistered_( ::osl::ResettableMutexGuard & guard, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) override; virtual void processPackage_( ::osl::ResettableMutexGuard & guard, bool registerPackage, bool startup, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) override; public: ComponentsPackageImpl( ::rtl::Reference const & myBackend, OUString const & url, OUString const & name, Reference const & xPackageType, bool bRemoved, OUString const & identifier); }; friend class ComponentsPackageImpl; class TypelibraryPackageImpl : public ::dp_registry::backend::Package { BackendImpl * getMyBackend() const; const bool m_jarFile; // Package virtual beans::Optional< beans::Ambiguous > isRegistered_( ::osl::ResettableMutexGuard & guard, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) override; virtual void processPackage_( ::osl::ResettableMutexGuard & guard, bool registerPackage, bool startup, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) override; public: TypelibraryPackageImpl( ::rtl::Reference const & myBackend, OUString const & url, OUString const & name, Reference const & xPackageType, bool jarFile, bool bRemoved, OUString const & identifier); }; friend class TypelibraryPackageImpl; /** Serves for unregistering packages that were registered on a different platform. This can happen if one has remotely mounted /home, for example. */ class OtherPlatformPackageImpl : public ::dp_registry::backend::Package { public: OtherPlatformPackageImpl( ::rtl::Reference const & myBackend, OUString const & url, OUString const & name, Reference const & xPackageType, bool bRemoved, OUString const & identifier, OUString const& rPlatform); private: BackendImpl * getMyBackend() const; Reference impl_openRDB() const; Reference impl_createInstance(OUString const& rService) const; // Package virtual beans::Optional< beans::Ambiguous > isRegistered_( ::osl::ResettableMutexGuard & guard, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) override; virtual void processPackage_( ::osl::ResettableMutexGuard & guard, bool registerPackage, bool startup, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) override; private: OUString const m_aPlatform; }; friend class OtherPlatformPackageImpl; std::deque m_jar_typelibs; std::deque m_rdb_typelibs; std::deque m_components; enum RcItem { RCITEM_JAR_TYPELIB, RCITEM_RDB_TYPELIB, RCITEM_COMPONENTS }; std::deque & getRcItemList( RcItem kind ) { switch (kind) { case RCITEM_JAR_TYPELIB: return m_jar_typelibs; case RCITEM_RDB_TYPELIB: return m_rdb_typelibs; default: // case RCITEM_COMPONENTS return m_components; } } bool m_unorc_inited; bool m_unorc_modified; bool bSwitchedRdbFiles; typedef std::unordered_map< OUString, Reference > t_string2object; t_string2object m_backendObjects; // PackageRegistryBackend virtual Reference bindPackage_( OUString const & url, OUString const & mediaType, bool bRemoved, OUString const & identifier, Reference const & xCmdEnv ) override; virtual void SAL_CALL disposing() override; const Reference m_xDynComponentTypeInfo; const Reference m_xJavaComponentTypeInfo; const Reference m_xPythonComponentTypeInfo; const Reference m_xComponentsTypeInfo; const Reference m_xRDBTypelibTypeInfo; const Reference m_xJavaTypelibTypeInfo; Sequence< Reference > m_typeInfos; OUString m_commonRDB; OUString m_nativeRDB; //URLs of the original rdbs (before any switching): OUString m_commonRDB_orig; OUString m_nativeRDB_orig; std::unique_ptr m_backendDb; void addDataToDb(OUString const & url, ComponentBackendDb::Data const & data); ComponentBackendDb::Data readDataFromDb(OUString const & url); void revokeEntryFromDb(OUString const & url); Reference m_xCommonRDB; Reference m_xNativeRDB; void unorc_verify_init( Reference const & xCmdEnv ); void unorc_flush( Reference const & xCmdEnv ); Reference getObject( OUString const & id ); Reference insertObject( OUString const & id, Reference const & xObject ); void releaseObject( OUString const & id ); void addToUnoRc( RcItem kind, OUString const & url, Reference const & xCmdEnv ); void removeFromUnoRc( RcItem kind, OUString const & url, Reference const & xCmdEnv ); bool hasInUnoRc( RcItem kind, OUString const & url ); css::uno::Reference< css::uno::XComponentContext > getRootContext() const; public: BackendImpl( Sequence const & args, Reference const & xComponentContext ); // XServiceInfo virtual OUString SAL_CALL getImplementationName() override; virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override; // XPackageRegistry virtual Sequence< Reference > SAL_CALL getSupportedPackageTypes() override; virtual void SAL_CALL packageRemoved(OUString const & url, OUString const & mediaType) override; using PackageRegistryBackend::disposing; //Will be called from ComponentPackageImpl void initServiceRdbFiles(); }; BackendImpl::ComponentPackageImpl::ComponentPackageImpl( ::rtl::Reference const & myBackend, OUString const & url, OUString const & name, Reference const & xPackageType, OUString const & loader, bool bRemoved, OUString const & identifier) : Package( myBackend, url, name, name /* display-name */, xPackageType, bRemoved, identifier), m_loader( loader ), m_registered( Reg::Uninit ) {} Reference BackendImpl::ComponentPackageImpl::getRDB() const { BackendImpl * that = getMyBackend(); //Late "initialization" of the services rdb files //This is to prevent problems when running several //instances of OOo with root rights in parallel. This //would otherwise cause problems when copying the rdbs. //See http://qa.openoffice.org/issues/show_bug.cgi?id=99257 { const ::osl::MutexGuard guard( getMutex() ); if (!that->bSwitchedRdbFiles) { that->bSwitchedRdbFiles = true; that->initServiceRdbFiles(); } } if ( m_loader == "com.sun.star.loader.SharedLibrary" ) return that->m_xNativeRDB; else return that->m_xCommonRDB; } BackendImpl * BackendImpl::ComponentPackageImpl::getMyBackend() const { BackendImpl * pBackend = static_cast(m_myBackend.get()); if (nullptr == pBackend) { //Throws a DisposedException check(); //We should never get here... throw RuntimeException( "Failed to get the BackendImpl", static_cast(const_cast(this))); } return pBackend; } void BackendImpl::disposing() { try { m_backendObjects = t_string2object(); if (m_xNativeRDB.is()) { m_xNativeRDB->close(); m_xNativeRDB.clear(); } if (m_xCommonRDB.is()) { m_xCommonRDB->close(); m_xCommonRDB.clear(); } unorc_flush( Reference() ); PackageRegistryBackend::disposing(); } catch (const RuntimeException &) { throw; } catch (const Exception &) { Any exc( ::cppu::getCaughtException() ); throw lang::WrappedTargetRuntimeException( "caught unexpected exception while disposing...", static_cast(this), exc ); } } void BackendImpl::initServiceRdbFiles() { const Reference xCmdEnv; ::ucbhelper::Content cacheDir( getCachePath(), xCmdEnv, m_xComponentContext ); ::ucbhelper::Content oldRDB; // switch common rdb: if (!m_commonRDB_orig.isEmpty()) { (void)create_ucb_content( &oldRDB, makeURL( getCachePath(), m_commonRDB_orig), xCmdEnv, false /* no throw */ ); } m_commonRDB = m_commonRDB_orig == "common.rdb" ? std::u16string_view(u"common_.rdb") : std::u16string_view(u"common.rdb"); if (oldRDB.get().is()) { cacheDir.transferContent( oldRDB, ::ucbhelper::InsertOperation::Copy, m_commonRDB, NameClash::OVERWRITE ); oldRDB = ::ucbhelper::Content(); } // switch native rdb: if (!m_nativeRDB_orig.isEmpty()) { (void)create_ucb_content( &oldRDB, makeURL(getCachePath(), m_nativeRDB_orig), xCmdEnv, false /* no throw */ ); } const OUString plt_rdb( getPlatformString() + ".rdb" ); const OUString plt_rdb_( getPlatformString() + "_.rdb" ); m_nativeRDB = (m_nativeRDB_orig == plt_rdb ) ? plt_rdb_ : plt_rdb; if (oldRDB.get().is()) { cacheDir.transferContent( oldRDB, ::ucbhelper::InsertOperation::Copy, m_nativeRDB, NameClash::OVERWRITE ); } // UNO is bootstrapped, flush for next process start: m_unorc_modified = true; unorc_flush( Reference() ); // common rdb for java, native rdb for shared lib components if (!m_commonRDB.isEmpty()) { m_xCommonRDB.set( m_xComponentContext->getServiceManager() ->createInstanceWithContext( "com.sun.star.registry.SimpleRegistry", m_xComponentContext ), UNO_QUERY_THROW ); m_xCommonRDB->open( makeURL( expandUnoRcUrl(getCachePath()), m_commonRDB ), false, true); } if (!m_nativeRDB.isEmpty()) { m_xNativeRDB.set( m_xComponentContext->getServiceManager() ->createInstanceWithContext( "com.sun.star.registry.SimpleRegistry", m_xComponentContext ), UNO_QUERY_THROW ); m_xNativeRDB->open( makeURL( expandUnoRcUrl(getCachePath()), m_nativeRDB ), false, true); } } BackendImpl::BackendImpl( Sequence const & args, Reference const & xComponentContext ) : PackageRegistryBackend( args, xComponentContext ), m_unorc_inited( false ), m_unorc_modified( false ), bSwitchedRdbFiles(false), m_xDynComponentTypeInfo( new Package::TypeInfo( "application/vnd.sun.star.uno-component;type=native;platform=" + getPlatformString(), "*" SAL_DLLEXTENSION, DpResId(RID_STR_DYN_COMPONENT) ) ), m_xJavaComponentTypeInfo( new Package::TypeInfo( "application/vnd.sun.star.uno-component;type=Java", "*.jar", DpResId(RID_STR_JAVA_COMPONENT) ) ), m_xPythonComponentTypeInfo( new Package::TypeInfo( "application/vnd.sun.star.uno-component;type=Python", "*.py", DpResId( RID_STR_PYTHON_COMPONENT) ) ), m_xComponentsTypeInfo( new Package::TypeInfo( "application/vnd.sun.star.uno-components", "*.components", DpResId(RID_STR_COMPONENTS) ) ), m_xRDBTypelibTypeInfo( new Package::TypeInfo( "application/vnd.sun.star.uno-typelibrary;type=RDB", "*.rdb", DpResId(RID_STR_RDB_TYPELIB) ) ), m_xJavaTypelibTypeInfo( new Package::TypeInfo( "application/vnd.sun.star.uno-typelibrary;type=Java", "*.jar", DpResId(RID_STR_JAVA_TYPELIB) ) ), m_typeInfos( 6 ) { m_typeInfos[ 0 ] = m_xDynComponentTypeInfo; m_typeInfos[ 1 ] = m_xJavaComponentTypeInfo; m_typeInfos[ 2 ] = m_xPythonComponentTypeInfo; m_typeInfos[ 3 ] = m_xComponentsTypeInfo; m_typeInfos[ 4 ] = m_xRDBTypelibTypeInfo; m_typeInfos[ 5 ] = m_xJavaTypelibTypeInfo; const Reference xCmdEnv; if (transientMode()) { // in-mem rdbs: // common rdb for java, native rdb for shared lib components m_xCommonRDB.set( xComponentContext->getServiceManager()->createInstanceWithContext( "com.sun.star.registry.SimpleRegistry", xComponentContext ), UNO_QUERY_THROW ); m_xCommonRDB->open( OUString() /* in-mem */, false /* ! read-only */, true /* create */ ); m_xNativeRDB.set( xComponentContext->getServiceManager()->createInstanceWithContext( "com.sun.star.registry.SimpleRegistry", xComponentContext ), UNO_QUERY_THROW ); m_xNativeRDB->open( OUString() /* in-mem */, false /* ! read-only */, true /* create */ ); } else { unorc_verify_init( xCmdEnv ); OUString dbFile = makeURL(getCachePath(), "backenddb.xml"); m_backendDb.reset( new ComponentBackendDb(getComponentContext(), dbFile)); } } // XServiceInfo OUString BackendImpl::getImplementationName() { return "com.sun.star.comp.deployment.component.PackageRegistryBackend"; } sal_Bool BackendImpl::supportsService( const OUString& ServiceName ) { return cppu::supportsService(this, ServiceName); } css::uno::Sequence< OUString > BackendImpl::getSupportedServiceNames() { return { BACKEND_SERVICE_NAME }; } void BackendImpl::addDataToDb( OUString const & url, ComponentBackendDb::Data const & data) { if (m_backendDb) m_backendDb->addEntry(url, data); } ComponentBackendDb::Data BackendImpl::readDataFromDb(OUString const & url) { ComponentBackendDb::Data data; if (m_backendDb) data = m_backendDb->getEntry(url); return data; } void BackendImpl::revokeEntryFromDb(OUString const & url) { if (m_backendDb) m_backendDb->revokeEntry(url); } // XPackageRegistry Sequence< Reference > BackendImpl::getSupportedPackageTypes() { return m_typeInfos; } void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/) { if (m_backendDb) m_backendDb->removeEntry(url); } // PackageRegistryBackend Reference BackendImpl::bindPackage_( OUString const & url, OUString const & mediaType_, bool bRemoved, OUString const & identifier, Reference const & xCmdEnv ) { OUString mediaType(mediaType_); if ( mediaType.isEmpty() || mediaType == "application/vnd.sun.star.uno-component" || mediaType == "application/vnd.sun.star.uno-typelibrary" ) { // detect exact media-type: ::ucbhelper::Content ucbContent; if (create_ucb_content( &ucbContent, url, xCmdEnv )) { const OUString title( StrTitle::getTitle( ucbContent ) ); if (title.endsWithIgnoreAsciiCase(SAL_DLLEXTENSION)) { mediaType = "application/vnd.sun.star.uno-component;type=native;platform=" + getPlatformString(); } else if (title.endsWithIgnoreAsciiCase(".jar")) { if (jarManifestHeaderPresent( url, "RegistrationClassName", xCmdEnv )) mediaType = "application/vnd.sun.star.uno-component;type=Java"; if (mediaType.isEmpty()) mediaType = "application/vnd.sun.star.uno-typelibrary;type=Java"; } else if (title.endsWithIgnoreAsciiCase(".py")) mediaType = "application/vnd.sun.star.uno-component;type=Python"; else if (title.endsWithIgnoreAsciiCase(".rdb")) mediaType = "application/vnd.sun.star.uno-typelibrary;type=RDB"; } if (mediaType.isEmpty()) throw lang::IllegalArgumentException( StrCannotDetectMediaType() + url, static_cast(this), static_cast(-1) ); } OUString type, subType; INetContentTypeParameterList params; if (INetContentTypes::parse( mediaType, type, subType, ¶ms )) { if (type.equalsIgnoreAsciiCase("application")) { OUString name; if (!bRemoved) { ::ucbhelper::Content ucbContent( url, xCmdEnv, m_xComponentContext ); name = StrTitle::getTitle( ucbContent ); } if (subType.equalsIgnoreAsciiCase("vnd.sun.star.uno-component")) { // xxx todo: probe and evaluate component xml description auto const iter = params.find(OString("platform")); bool bPlatformFits(iter == params.end()); OUString aPlatform; if (!bPlatformFits) // platform is specified, we have to check { aPlatform = iter->second.m_sValue; bPlatformFits = platform_fits(aPlatform); } // If the package is being removed, do not care whether // platform fits. We won't be using it anyway. if (bPlatformFits || bRemoved) { auto const iterType = params.find(OString("type")); if (iterType != params.end()) { OUString const & value = iterType->second.m_sValue; if (value.equalsIgnoreAsciiCase("native")) { if (bPlatformFits) return new BackendImpl::ComponentPackageImpl( this, url, name, m_xDynComponentTypeInfo, "com.sun.star.loader.SharedLibrary", bRemoved, identifier); else return new BackendImpl::OtherPlatformPackageImpl( this, url, name, m_xDynComponentTypeInfo, bRemoved, identifier, aPlatform); } if (value.equalsIgnoreAsciiCase("Java")) { return new BackendImpl::ComponentPackageImpl( this, url, name, m_xJavaComponentTypeInfo, "com.sun.star.loader.Java2", bRemoved, identifier); } if (value.equalsIgnoreAsciiCase("Python")) { return new BackendImpl::ComponentPackageImpl( this, url, name, m_xPythonComponentTypeInfo, "com.sun.star.loader.Python", bRemoved, identifier); } } } } else if (subType.equalsIgnoreAsciiCase("vnd.sun.star.uno-components")) { auto const iter = params.find(OString("platform")); if (iter == params.end() || platform_fits(iter->second.m_sValue)) { return new BackendImpl::ComponentsPackageImpl( this, url, name, m_xComponentsTypeInfo, bRemoved, identifier); } } else if (subType.equalsIgnoreAsciiCase( "vnd.sun.star.uno-typelibrary")) { auto const iter = params.find(OString("type")); if (iter != params.end()) { OUString const & value = iter->second.m_sValue; if (value.equalsIgnoreAsciiCase("RDB")) { return new BackendImpl::TypelibraryPackageImpl( this, url, name, m_xRDBTypelibTypeInfo, false /* rdb */, bRemoved, identifier); } if (value.equalsIgnoreAsciiCase("Java")) { return new BackendImpl::TypelibraryPackageImpl( this, url, name, m_xJavaTypelibTypeInfo, true /* jar */, bRemoved, identifier); } } } } } throw lang::IllegalArgumentException( StrUnsupportedMediaType() + mediaType, static_cast(this), static_cast(-1) ); } void BackendImpl::unorc_verify_init( Reference const & xCmdEnv ) { if (transientMode()) return; const ::osl::MutexGuard guard( getMutex() ); if ( m_unorc_inited) return; // common rc: ::ucbhelper::Content ucb_content; if (create_ucb_content( &ucb_content, makeURL( getCachePath(), "unorc" ), xCmdEnv, false /* no throw */ )) { OUString line; if (readLine( &line, "UNO_JAVA_CLASSPATH=", ucb_content, RTL_TEXTENCODING_UTF8 )) { sal_Int32 index = sizeof ("UNO_JAVA_CLASSPATH=") - 1; do { OUString token( line.getToken( 0, ' ', index ).trim() ); if (!token.isEmpty()) { if (create_ucb_content( nullptr, expandUnoRcTerm(token), xCmdEnv, false /* no throw */ )) { //The jar file may not exist anymore if a shared or bundled //extension was removed, but it can still be in the unorc //After running XExtensionManager::synchronize, the unorc is //cleaned up m_jar_typelibs.push_back( token ); } } } while (index >= 0); } if (readLine( &line, "UNO_TYPES=", ucb_content, RTL_TEXTENCODING_UTF8 )) { sal_Int32 index = sizeof ("UNO_TYPES=") - 1; do { OUString token( line.getToken( 0, ' ', index ).trim() ); if (!token.isEmpty()) { if (token[ 0 ] == '?') token = token.copy( 1 ); if (create_ucb_content( nullptr, expandUnoRcTerm(token), xCmdEnv, false /* no throw */ )) { //The RDB file may not exist anymore if a shared or bundled //extension was removed, but it can still be in the unorc. //After running XExtensionManager::synchronize, the unorc is //cleaned up m_rdb_typelibs.push_back( token ); } } } while (index >= 0); } if (readLine( &line, "UNO_SERVICES=", ucb_content, RTL_TEXTENCODING_UTF8 )) { // The UNO_SERVICES line always has the BNF form // "UNO_SERVICES=" // ("?$ORIGIN/" )? -- first // "${$ORIGIN/${_OS}_${_ARCH}rc:UNO_SERVICES}"? -- second // ("?" ("BUNDLED_EXTENSIONS" | -- third // "UNO_SHARED_PACKAGES_CACHE" | "UNO_USER_PACKAGES_CACHE") // ...)* // so can unambiguously be split into its three parts: int state = 1; for (sal_Int32 i = RTL_CONSTASCII_LENGTH("UNO_SERVICES="); i >= 0;) { OUString token(line.getToken(0, ' ', i)); if (!token.isEmpty()) { if (state == 1 && token.match("?$ORIGIN/")) { m_commonRDB_orig = token.copy( RTL_CONSTASCII_LENGTH("?$ORIGIN/")); state = 2; } else if ( state <= 2 && token == "${$ORIGIN/${_OS}_${_ARCH}rc:UNO_SERVICES}" ) { state = 3; } else { if (token[0] == '?') { token = token.copy(1); } m_components.push_back(token); state = 3; } } } } // native rc: if (create_ucb_content( &ucb_content, makeURL( getCachePath(), getPlatformString() + "rc"), xCmdEnv, false /* no throw */ )) { if (readLine( &line, "UNO_SERVICES=", ucb_content, RTL_TEXTENCODING_UTF8 )) { m_nativeRDB_orig = line.copy( sizeof ("UNO_SERVICES=?$ORIGIN/") - 1 ); } } } m_unorc_modified = false; m_unorc_inited = true; } void BackendImpl::unorc_flush( Reference const & xCmdEnv ) { if (transientMode()) return; if (!m_unorc_inited || !m_unorc_modified) return; OStringBuffer buf; buf.append("ORIGIN="); OUString sOrigin = dp_misc::makeRcTerm(m_cachePath); OString osOrigin = OUStringToOString(sOrigin, RTL_TEXTENCODING_UTF8); buf.append(osOrigin); buf.append(LF); if (! m_jar_typelibs.empty()) { auto iPos( m_jar_typelibs.cbegin() ); auto const iEnd( m_jar_typelibs.cend() ); buf.append( "UNO_JAVA_CLASSPATH=" ); while (iPos != iEnd) { // encoded ASCII file-urls: const OString item( OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); buf.append( item ); ++iPos; if (iPos != iEnd) buf.append( ' ' ); } buf.append(LF); } if (! m_rdb_typelibs.empty()) { auto iPos( m_rdb_typelibs.cbegin() ); auto const iEnd( m_rdb_typelibs.cend() ); buf.append( "UNO_TYPES=" ); while (iPos != iEnd) { buf.append( '?' ); // encoded ASCII file-urls: const OString item( OUStringToOString( *iPos, RTL_TEXTENCODING_ASCII_US ) ); buf.append( item ); ++iPos; if (iPos != iEnd) buf.append( ' ' ); } buf.append(LF); } // If we duplicated the common or native rdb then we must use those urls //otherwise we use those of the original files. That is, m_commonRDB_orig //and m_nativeRDB_orig; OUString sCommonRDB(m_commonRDB.isEmpty() ? m_commonRDB_orig : m_commonRDB ); OUString sNativeRDB(m_nativeRDB.isEmpty() ? m_nativeRDB_orig : m_nativeRDB ); if (!sCommonRDB.isEmpty() || !sNativeRDB.isEmpty() || !m_components.empty()) { buf.append( "UNO_SERVICES=" ); bool space = false; if (!sCommonRDB.isEmpty()) { buf.append( "?$ORIGIN/" ); buf.append( OUStringToOString( sCommonRDB, RTL_TEXTENCODING_ASCII_US ) ); space = true; } if (!sNativeRDB.isEmpty()) { if (space) { buf.append(' '); } buf.append( "${$ORIGIN/${_OS}_${_ARCH}rc:UNO_SERVICES}" ); space = true; // write native rc: OString buf2 = "ORIGIN=" + osOrigin + OStringChar(LF) + "UNO_SERVICES=?$ORIGIN/" + OUStringToOString( sNativeRDB, RTL_TEXTENCODING_ASCII_US ) + OStringChar(LF); const Reference xData( ::xmlscript::createInputStream( reinterpret_cast(buf2.getStr()), buf2.getLength() ) ); ::ucbhelper::Content ucb_content( makeURL( getCachePath(), getPlatformString() + "rc" ), xCmdEnv, m_xComponentContext ); ucb_content.writeStream( xData, true /* replace existing */ ); } for (auto const& component : m_components) { if (space) { buf.append(' '); } buf.append('?'); buf.append(OUStringToOString(component, RTL_TEXTENCODING_UTF8)); space = true; } buf.append(LF); } // write unorc: const Reference xData( ::xmlscript::createInputStream( reinterpret_cast(buf.getStr()), buf.getLength() ) ); ::ucbhelper::Content ucb_content( makeURL( getCachePath(), "unorc" ), xCmdEnv, m_xComponentContext ); ucb_content.writeStream( xData, true /* replace existing */ ); m_unorc_modified = false; } void BackendImpl::addToUnoRc( RcItem kind, OUString const & url_, Reference const & xCmdEnv ) { const OUString rcterm( dp_misc::makeRcTerm(url_) ); const ::osl::MutexGuard guard( getMutex() ); unorc_verify_init( xCmdEnv ); std::deque & rSet = getRcItemList(kind); if (std::find( rSet.begin(), rSet.end(), rcterm ) == rSet.end()) { rSet.push_front( rcterm ); // prepend to list, thus overriding // write immediately: m_unorc_modified = true; unorc_flush( xCmdEnv ); } } void BackendImpl::removeFromUnoRc( RcItem kind, OUString const & url_, Reference const & xCmdEnv ) { const OUString rcterm( dp_misc::makeRcTerm(url_) ); const ::osl::MutexGuard guard( getMutex() ); unorc_verify_init( xCmdEnv ); std::deque & aRcItemList = getRcItemList(kind); aRcItemList.erase(std::remove(aRcItemList.begin(), aRcItemList.end(), rcterm), aRcItemList.end()); // write immediately: m_unorc_modified = true; unorc_flush( xCmdEnv ); } bool BackendImpl::hasInUnoRc( RcItem kind, OUString const & url_ ) { const OUString rcterm( dp_misc::makeRcTerm(url_) ); const ::osl::MutexGuard guard( getMutex() ); std::deque const & rSet = getRcItemList(kind); return std::find( rSet.begin(), rSet.end(), rcterm ) != rSet.end(); } css::uno::Reference< css::uno::XComponentContext > BackendImpl::getRootContext() const { css::uno::Reference< css::uno::XComponentContext > rootContext( getComponentContext()->getValueByName("_root"), css::uno::UNO_QUERY); return rootContext.is() ? rootContext : getComponentContext(); } void BackendImpl::releaseObject( OUString const & id ) { const ::osl::MutexGuard guard( getMutex() ); m_backendObjects.erase( id ); } Reference BackendImpl::getObject( OUString const & id ) { const ::osl::MutexGuard guard( getMutex() ); const t_string2object::const_iterator iFind( m_backendObjects.find( id ) ); if (iFind == m_backendObjects.end()) return Reference(); else return iFind->second; } Reference BackendImpl::insertObject( OUString const & id, Reference const & xObject ) { const ::osl::MutexGuard guard( getMutex() ); const std::pair insertion( m_backendObjects.emplace( id, xObject ) ); return insertion.first->second; } Reference raise_uno_process( Reference const & xContext, ::rtl::Reference const & abortChannel ) { OSL_ASSERT( xContext.is() ); OUString url( util::theMacroExpander::get(xContext)->expandMacros( "$URE_BIN_DIR/uno" ) ); const OUString connectStr = "uno:pipe,name=" + generateRandomPipeId() + ";urp;uno.ComponentContext"; // raise core UNO process to register/run a component, // javavm service uses unorc next to executable to retrieve deployed // jar typelibs std::vector args{ #if OSL_DEBUG_LEVEL == 0 "--quiet", #endif "--singleaccept", "-u", connectStr, // don't inherit from unorc: "-env:INIFILENAME=" }; //now add the bootstrap variables which were supplied on the command line std::vector bootvars = getCmdBootstrapVariables(); args.insert(args.end(), bootvars.begin(), bootvars.end()); oslProcess hProcess; try { hProcess = raiseProcess( url, comphelper::containerToSequence(args) ); } catch (...) { OUStringBuffer sMsg = "error starting process: " + url; for(const auto& arg : args) sMsg.append(" ").append(arg); throw uno::RuntimeException(sMsg.makeStringAndClear()); } try { return Reference( resolveUnoURL( connectStr, xContext, abortChannel.get() ), UNO_QUERY_THROW ); } catch (...) { // try to terminate process: if ( osl_terminateProcess( hProcess ) != osl_Process_E_None ) { OSL_ASSERT( false ); } throw; } } void extractComponentData( css::uno::Reference< css::uno::XComponentContext > const & context, css::uno::Reference< css::registry::XRegistryKey > const & registry, ComponentBackendDb::Data * data, std::vector< css::uno::Reference< css::uno::XInterface > > * factories, css::uno::Reference< css::loader::XImplementationLoader > const & componentLoader, OUString const & componentUrl) { OSL_ASSERT( context.is() && registry.is() && data != nullptr && componentLoader.is()); OUString registryName(registry->getKeyName()); sal_Int32 prefix = registryName.getLength(); if (!registryName.endsWith("/")) { prefix += RTL_CONSTASCII_LENGTH("/"); } const css::uno::Sequence< css::uno::Reference< css::registry::XRegistryKey > > keys(registry->openKeys()); css::uno::Reference< css::lang::XMultiComponentFactory > smgr( context->getServiceManager(), css::uno::UNO_SET_THROW); for (css::uno::Reference< css::registry::XRegistryKey > const & key : keys) { OUString name(key->getKeyName().copy(prefix)); data->implementationNames.push_back(name); css::uno::Reference< css::registry::XRegistryKey > singletons( key->openKey("UNO/SINGLETONS")); if (singletons.is()) { sal_Int32 prefix2 = key->getKeyName().getLength() + RTL_CONSTASCII_LENGTH("/UNO/SINGLETONS/"); const css::uno::Sequence< css::uno::Reference< css::registry::XRegistryKey > > singletonKeys(singletons->openKeys()); for (css::uno::Reference< css::registry::XRegistryKey > const & singletonKey : singletonKeys) { data->singletons.emplace_back( singletonKey->getKeyName().copy(prefix2), name); } } if (factories != nullptr) { factories->push_back( componentLoader->activate( name, OUString(), componentUrl, key)); } } } void BackendImpl::ComponentPackageImpl::getComponentInfo( ComponentBackendDb::Data * data, std::vector< css::uno::Reference< css::uno::XInterface > > * factories, Reference const & xContext ) { const Reference xLoader( xContext->getServiceManager()->createInstanceWithContext( m_loader, xContext ), UNO_QUERY ); if (! xLoader.is()) { throw css::deployment::DeploymentException( "cannot instantiate loader " + m_loader, static_cast< OWeakObject * >(this), Any()); } // HACK: highly dependent on stoc/source/servicemanager // and stoc/source/implreg implementation which rely on the same // services.rdb format! // .../UNO/LOCATION and .../UNO/ACTIVATOR appear not to be written by // writeRegistryInfo, however, but are known, fixed values here, so // can be passed into extractComponentData OUString url(getURL()); const Reference xMemReg( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.registry.SimpleRegistry", xContext ), UNO_QUERY_THROW ); xMemReg->open( OUString() /* in mem */, false, true ); xLoader->writeRegistryInfo( xMemReg->getRootKey(), OUString(), url ); extractComponentData( xContext, xMemReg->getRootKey(), data, factories, xLoader, url); } void BackendImpl::ComponentPackageImpl::componentLiveInsertion( ComponentBackendDb::Data const & data, std::vector< css::uno::Reference< css::uno::XInterface > > const & factories) { css::uno::Reference< css::uno::XComponentContext > rootContext( getMyBackend()->getRootContext()); css::uno::Reference< css::container::XSet > set( rootContext->getServiceManager(), css::uno::UNO_QUERY_THROW); std::vector< css::uno::Reference< css::uno::XInterface > >::const_iterator factory(factories.begin()); for (auto const& implementationName : data.implementationNames) { try { set->insert(css::uno::Any(*factory++)); } catch (const container::ElementExistException &) { SAL_WARN("desktop.deployment", "implementation already registered " << implementationName); } } if (data.singletons.empty()) return; css::uno::Reference< css::container::XNameContainer > cont( rootContext, css::uno::UNO_QUERY_THROW); for (auto const& singleton : data.singletons) { OUString name("/singletons/" + singleton.first); //TODO: Update should be atomic: try { cont->removeByName( name + "/arguments"); } catch (const container::NoSuchElementException &) {} try { cont->insertByName( name + "/service", css::uno::Any(singleton.second)); } catch (const container::ElementExistException &) { cont->replaceByName( name + "/service", css::uno::Any(singleton.second)); } try { cont->insertByName(name, css::uno::Any()); } catch (const container::ElementExistException &) { SAL_WARN("desktop.deployment", "singleton already registered " << singleton.first); cont->replaceByName(name, css::uno::Any()); } } } void BackendImpl::ComponentPackageImpl::componentLiveRemoval( ComponentBackendDb::Data const & data) { css::uno::Reference< css::uno::XComponentContext > rootContext( getMyBackend()->getRootContext()); css::uno::Reference< css::container::XSet > set( rootContext->getServiceManager(), css::uno::UNO_QUERY_THROW); for (auto const& implementationName : data.implementationNames) { try { set->remove(css::uno::Any(implementationName)); } catch (const css::container::NoSuchElementException &) { // ignore if factory has not been live deployed } } if (data.singletons.empty()) return; css::uno::Reference< css::container::XNameContainer > cont( rootContext, css::uno::UNO_QUERY_THROW); for (auto const& singleton : data.singletons) { OUString name("/singletons/" + singleton.first); //TODO: Removal should be atomic: try { cont->removeByName(name); } catch (const container::NoSuchElementException &) {} try { cont->removeByName( name + "/service" ); } catch (const container::NoSuchElementException &) {} try { cont->removeByName( name + "/arguments" ); } catch (const container::NoSuchElementException &) {} } } // Package //We could use here BackendImpl::hasActiveEntry. However, this check is just as well. //And it also shows the problem if another extension has overwritten an implementation //entry, because it contains the same service implementation beans::Optional< beans::Ambiguous > BackendImpl::ComponentPackageImpl::isRegistered_( ::osl::ResettableMutexGuard &, ::rtl::Reference const & abortChannel, Reference const & ) { if (m_registered == Reg::Uninit) { m_registered = Reg::NotRegistered; const Reference xRDB( getRDB() ); if (xRDB.is()) { bool bAmbiguousComponentName = false; // lookup rdb for location URL: const Reference xRootKey( xRDB->getRootKey() ); const Reference xImplKey( xRootKey->openKey( "IMPLEMENTATIONS" ) ); Sequence implNames; if (xImplKey.is() && xImplKey->isValid()) implNames = xImplKey->getKeyNames(); OUString const * pImplNames = implNames.getConstArray(); sal_Int32 pos = implNames.getLength(); for ( ; pos--; ) { checkAborted( abortChannel ); const OUString key( pImplNames[ pos ] + "/UNO/LOCATION" ); const Reference xKey( xRootKey->openKey(key) ); if (xKey.is() && xKey->isValid()) { const OUString location( xKey->getAsciiValue() ); if (location.equalsIgnoreAsciiCase( getURL() )) { break; } else { //try to match only the file name OUString thisUrl(getURL()); OUString thisFileName(thisUrl.copy(thisUrl.lastIndexOf('/'))); OUString locationFileName(location.copy(location.lastIndexOf('/'))); if (locationFileName.equalsIgnoreAsciiCase(thisFileName)) bAmbiguousComponentName = true; } } } if (pos >= 0) m_registered = Reg::Registered; else if (bAmbiguousComponentName) m_registered = Reg::MaybeRegistered; } } //Different extensions can use the same service implementations. Then the extensions //which was installed last will overwrite the one from the other extension. That is //the registry will contain the path (the location) of the library or jar of the //second extension. In this case isRegistered called for the lib of the first extension //would return "not registered". That would mean that during uninstallation //XPackage::registerPackage is not called, because it just was not registered. This is, //however, necessary for jar files. Registering and unregistering update //uno_packages/cache/registry/com.sun.star.comp.deployment.component.PackageRegistryBackend/unorc //Therefore, we will return always "is ambiguous" if the path of this component cannot //be found in the registry and if there is another path and both have the same file name (but //the rest of the path is different). //If the caller cannot precisely determine that this package was registered, then it must //call registerPackage. bool bAmbiguous = m_registered == Reg::Void // Reg::Void == we are in the progress of unregistration || m_registered == Reg::MaybeRegistered; return beans::Optional< beans::Ambiguous >( true /* IsPresent */, beans::Ambiguous( m_registered == Reg::Registered, bAmbiguous) ); } void BackendImpl::ComponentPackageImpl::processPackage_( ::osl::ResettableMutexGuard &, bool doRegisterPackage, bool startup, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) { BackendImpl * that = getMyBackend(); OUString url(getURL()); if (doRegisterPackage) { ComponentBackendDb::Data data; css::uno::Reference< css::uno::XComponentContext > context; if (startup) { context = that->getComponentContext(); } else { context.set(that->getObject(url), css::uno::UNO_QUERY); if (!context.is()) { context.set( that->insertObject( url, raise_uno_process( that->getComponentContext(), abortChannel)), css::uno::UNO_QUERY_THROW); } } css::uno::Reference< css::registry::XImplementationRegistration> impreg( context->getServiceManager()->createInstanceWithContext( "com.sun.star.registry.ImplementationRegistration", context), css::uno::UNO_QUERY_THROW); css::uno::Reference< css::registry::XSimpleRegistry > rdb(getRDB()); impreg->registerImplementation(m_loader, url, rdb); // Only write to unorc after successful registration; it may fail if // there is no suitable java if (m_loader == "com.sun.star.loader.Java2" && !jarManifestHeaderPresent(url, "UNO-Type-Path", xCmdEnv)) { that->addToUnoRc(RCITEM_JAR_TYPELIB, url, xCmdEnv); data.javaTypeLibrary = true; } std::vector< css::uno::Reference< css::uno::XInterface > > factories; getComponentInfo(&data, startup ? nullptr : &factories, context); if (!startup) { try { componentLiveInsertion(data, factories); } catch (css::uno::Exception &) { TOOLS_INFO_EXCEPTION("desktop.deployment", "caught"); try { impreg->revokeImplementation(url, rdb); } catch (css::uno::RuntimeException &) { TOOLS_WARN_EXCEPTION("desktop.deployment", "ignored"); } throw; } } m_registered = Reg::Registered; that->addDataToDb(url, data); } else { // revoke m_registered = Reg::Void; ComponentBackendDb::Data data(that->readDataFromDb(url)); css::uno::Reference< css::uno::XComponentContext > context( that->getObject(url), css::uno::UNO_QUERY); bool remoteContext = context.is(); if (!remoteContext) { context = that->getComponentContext(); } if (!startup) { componentLiveRemoval(data); } css::uno::Reference< css::registry::XImplementationRegistration >( context->getServiceManager()->createInstanceWithContext( "com.sun.star.registry.ImplementationRegistration", context), css::uno::UNO_QUERY_THROW)->revokeImplementation(url, getRDB()); if (data.javaTypeLibrary) { that->removeFromUnoRc(RCITEM_JAR_TYPELIB, url, xCmdEnv); } if (remoteContext) { that->releaseObject(url); } m_registered = Reg::NotRegistered; getMyBackend()->revokeEntryFromDb(url); } } BackendImpl::TypelibraryPackageImpl::TypelibraryPackageImpl( ::rtl::Reference const & myBackend, OUString const & url, OUString const & name, Reference const & xPackageType, bool jarFile, bool bRemoved, OUString const & identifier) : Package( myBackend, url, name, name /* display-name */, xPackageType, bRemoved, identifier), m_jarFile( jarFile ) { } // Package BackendImpl * BackendImpl::TypelibraryPackageImpl::getMyBackend() const { BackendImpl * pBackend = static_cast(m_myBackend.get()); if (nullptr == pBackend) { //May throw a DisposedException check(); //We should never get here... throw RuntimeException( "Failed to get the BackendImpl", static_cast(const_cast(this))); } return pBackend; } beans::Optional< beans::Ambiguous > BackendImpl::TypelibraryPackageImpl::isRegistered_( ::osl::ResettableMutexGuard &, ::rtl::Reference const &, Reference const & ) { BackendImpl * that = getMyBackend(); return beans::Optional< beans::Ambiguous >( true /* IsPresent */, beans::Ambiguous( that->hasInUnoRc( m_jarFile ? RCITEM_JAR_TYPELIB : RCITEM_RDB_TYPELIB, getURL() ), false /* IsAmbiguous */ ) ); } void BackendImpl::TypelibraryPackageImpl::processPackage_( ::osl::ResettableMutexGuard &, bool doRegisterPackage, bool /*startup*/, ::rtl::Reference const &, Reference const & xCmdEnv ) { BackendImpl * that = getMyBackend(); const OUString url( getURL() ); if (doRegisterPackage) { // live insertion: if (m_jarFile) { // xxx todo add to classpath at runtime: ??? //SB: It is probably not worth it to add the live inserted type // library JAR to the UnoClassLoader in the soffice process. Any // live inserted component JAR that might reference this type // library JAR runs in its own uno process, so there is probably no // Java code in the soffice process that would see any UNO types // introduced by this type library JAR. } else // RDB: { css::uno::Reference< css::container::XSet >( that->getComponentContext()->getValueByName( "/singletons" "/com.sun.star.reflection.theTypeDescriptionManager"), css::uno::UNO_QUERY_THROW)->insert( css::uno::makeAny(expandUnoRcUrl(url))); } that->addToUnoRc( m_jarFile ? RCITEM_JAR_TYPELIB : RCITEM_RDB_TYPELIB, url, xCmdEnv ); } else // revokePackage() { that->removeFromUnoRc( m_jarFile ? RCITEM_JAR_TYPELIB : RCITEM_RDB_TYPELIB, url, xCmdEnv ); // revoking types at runtime, possible, sensible? if (!m_jarFile) { css::uno::Reference< css::container::XSet >( that->getComponentContext()->getValueByName( "/singletons" "/com.sun.star.reflection.theTypeDescriptionManager"), css::uno::UNO_QUERY_THROW)->remove( css::uno::makeAny(expandUnoRcUrl(url))); } } } BackendImpl::OtherPlatformPackageImpl::OtherPlatformPackageImpl( ::rtl::Reference const & myBackend, OUString const & url, OUString const & name, Reference const & xPackageType, bool bRemoved, OUString const & identifier, OUString const& rPlatform) : Package(myBackend, url, name, name, xPackageType, bRemoved, identifier) , m_aPlatform(rPlatform) { OSL_PRECOND(bRemoved, "this class can only be used for removing packages!"); } BackendImpl * BackendImpl::OtherPlatformPackageImpl::getMyBackend() const { BackendImpl * pBackend = static_cast(m_myBackend.get()); if (nullptr == pBackend) { //Throws a DisposedException check(); //We should never get here... throw RuntimeException("Failed to get the BackendImpl", static_cast(const_cast(this))); } return pBackend; } Reference BackendImpl::OtherPlatformPackageImpl::impl_openRDB() const { OUString const aRDB(m_aPlatform + ".rdb"); OUString const aRDBPath(makeURL(getMyBackend()->getCachePath(), aRDB)); Reference xRegistry; try { xRegistry.set( impl_createInstance("com.sun.star.registry.SimpleRegistry"), UNO_QUERY) ; if (xRegistry.is()) xRegistry->open(expandUnoRcUrl(aRDBPath), false, false); } catch (registry::InvalidRegistryException const&) { // If the registry does not exist, we do not need to bother at all xRegistry.set(nullptr); } SAL_WARN_IF( !xRegistry.is(), "desktop.deployment", "could not create registry for the package's platform"); return xRegistry; } Reference BackendImpl::OtherPlatformPackageImpl::impl_createInstance(OUString const& rService) const { Reference const xContext(getMyBackend()->getComponentContext()); OSL_ASSERT(xContext.is()); Reference xService; if (xContext.is()) xService.set(xContext->getServiceManager()->createInstanceWithContext(rService, xContext)); return xService; } beans::Optional > BackendImpl::OtherPlatformPackageImpl::isRegistered_( ::osl::ResettableMutexGuard& /* guard */, ::rtl::Reference const& /* abortChannel */, Reference const& /* xCmdEnv */ ) { return beans::Optional >(true, beans::Ambiguous(true, false)); } void BackendImpl::OtherPlatformPackageImpl::processPackage_( ::osl::ResettableMutexGuard& /* guard */, bool bRegisterPackage, bool /* bStartup */, ::rtl::Reference const& /* abortChannel */, Reference const& /* xCmdEnv */) { OSL_PRECOND(!bRegisterPackage, "this class can only be used for removing packages!"); OUString const aURL(getURL()); Reference const xServicesRDB(impl_openRDB()); Reference const xImplReg( impl_createInstance("com.sun.star.registry.ImplementationRegistration"), UNO_QUERY) ; if (xImplReg.is() && xServicesRDB.is()) xImplReg->revokeImplementation(aURL, xServicesRDB); if (xServicesRDB.is()) xServicesRDB->close(); getMyBackend()->revokeEntryFromDb(aURL); } BackendImpl * BackendImpl::ComponentsPackageImpl::getMyBackend() const { BackendImpl * pBackend = static_cast(m_myBackend.get()); if (nullptr == pBackend) { //Throws a DisposedException check(); //We should never get here... throw RuntimeException("Failed to get the BackendImpl", static_cast(const_cast(this))); } return pBackend; } beans::Optional< beans::Ambiguous > BackendImpl::ComponentsPackageImpl::isRegistered_( ::osl::ResettableMutexGuard &, ::rtl::Reference const &, Reference const & ) { return beans::Optional< beans::Ambiguous >( true, beans::Ambiguous( getMyBackend()->hasInUnoRc(RCITEM_COMPONENTS, getURL()), false)); } void BackendImpl::ComponentsPackageImpl::processPackage_( ::osl::ResettableMutexGuard &, bool doRegisterPackage, bool startup, ::rtl::Reference const & abortChannel, Reference const & xCmdEnv ) { BackendImpl * that = getMyBackend(); OUString url(getURL()); if (doRegisterPackage) { if (!startup) { css::uno::Reference< css::uno::XComponentContext > context( that->getObject(url), css::uno::UNO_QUERY); if (!context.is()) { context.set( that->insertObject( url, raise_uno_process( that->getComponentContext(), abortChannel)), css::uno::UNO_QUERY_THROW); } // This relies on the root component context's service manager // supporting the extended XSet semantics: css::uno::Sequence< css::beans::NamedValue > args { { "uri", css::uno::makeAny(expandUnoRcUrl(url)) }, { "component-context", css::uno::makeAny(context) } }; css::uno::Reference< css::container::XSet > smgr( that->getRootContext()->getServiceManager(), css::uno::UNO_QUERY_THROW); smgr->insert(css::uno::makeAny(args)); } that->addToUnoRc(RCITEM_COMPONENTS, url, xCmdEnv); } else { // revoke that->removeFromUnoRc(RCITEM_COMPONENTS, url, xCmdEnv); if (!startup) { // This relies on the root component context's service manager // supporting the extended XSet semantics: css::uno::Sequence< css::beans::NamedValue > args { { "uri", css::uno::makeAny(expandUnoRcUrl(url)) } }; css::uno::Reference< css::container::XSet > smgr( that->getRootContext()->getServiceManager(), css::uno::UNO_QUERY_THROW); smgr->remove(css::uno::makeAny(args)); } that->releaseObject(url); that->revokeEntryFromDb(url); // in case it got added with old code } } BackendImpl::ComponentsPackageImpl::ComponentsPackageImpl( ::rtl::Reference const & myBackend, OUString const & url, OUString const & name, Reference const & xPackageType, bool bRemoved, OUString const & identifier) : Package( myBackend, url, name, name /* display-name */, xPackageType, bRemoved, identifier) {} } // anon namespace } // namespace dp_registry extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* com_sun_star_comp_deployment_component_PackageRegistryBackend_get_implementation( css::uno::XComponentContext* context, css::uno::Sequence const& args) { return cppu::acquire(new dp_registry::backend::component::BackendImpl(args, context)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */