diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /desktop/source/deployment/registry/component | |
parent | Initial commit. (diff) | |
download | libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.tar.xz libreoffice-940b4d1848e8c70ab7642901a68594e8016caffc.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'desktop/source/deployment/registry/component')
3 files changed, 1935 insertions, 0 deletions
diff --git a/desktop/source/deployment/registry/component/dp_compbackenddb.cxx b/desktop/source/deployment/registry/component/dp_compbackenddb.cxx new file mode 100644 index 000000000..05f265404 --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_compbackenddb.cxx @@ -0,0 +1,131 @@ +/* -*- 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 <cppuhelper/exc_hlp.hxx> +#include <com/sun/star/deployment/DeploymentException.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include "dp_compbackenddb.hxx" + + +using namespace ::com::sun::star::uno; + +#define EXTENSION_REG_NS "http://openoffice.org/extensionmanager/component-registry/2010" +#define NS_PREFIX "comp" +#define ROOT_ELEMENT_NAME "component-backend-db" +#define KEY_ELEMENT_NAME "component" + +namespace dp_registry::backend::component { + +ComponentBackendDb::ComponentBackendDb( + Reference<XComponentContext> const & xContext, + OUString const & url):BackendDb(xContext, url) +{ + +} + +OUString ComponentBackendDb::getDbNSName() +{ + return EXTENSION_REG_NS; +} + +OUString ComponentBackendDb::getNSPrefix() +{ + return NS_PREFIX; +} + +OUString ComponentBackendDb::getRootElementName() +{ + return ROOT_ELEMENT_NAME; +} + +OUString ComponentBackendDb::getKeyElementName() +{ + return KEY_ELEMENT_NAME; +} + +void ComponentBackendDb::addEntry(OUString const & url, Data const & data) +{ + try{ + if (!activateEntry(url)) + { + Reference<css::xml::dom::XNode> componentNode = writeKeyElement(url); + writeSimpleElement("java-type-library", + OUString::boolean(data.javaTypeLibrary), + componentNode); + + writeSimpleList( + data.implementationNames, + "implementation-names", + "name", + componentNode); + + writeVectorOfPair( + data.singletons, + "singletons", + "item", + "key", + "value", + componentNode); + + save(); + } + } + catch(const css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + "Extension Manager: failed to write data entry in backend db: " + + m_urlDb, nullptr, exc); + } +} + +ComponentBackendDb::Data ComponentBackendDb::getEntry(OUString const & url) +{ + try + { + ComponentBackendDb::Data retData; + Reference<css::xml::dom::XNode> aNode = getKeyElement(url); + if (aNode.is()) + { + bool bJava = readSimpleElement("java-type-library", aNode) == "true"; + retData.javaTypeLibrary = bJava; + + retData.implementationNames = + readList( aNode, "implementation-names", "name"); + + retData.singletons = + readVectorOfPair( aNode, "singletons", "item", "key", "value"); + } + return retData; + } + catch(const css::uno::Exception &) + { + Any exc( ::cppu::getCaughtException() ); + throw css::deployment::DeploymentException( + "Extension Manager: failed to read data entry in backend db: " + + m_urlDb, nullptr, exc); + } +} + + +} // namespace dp_registry::backend::component + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/component/dp_compbackenddb.hxx b/desktop/source/deployment/registry/component/dp_compbackenddb.hxx new file mode 100644 index 000000000..b7bcdf50a --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_compbackenddb.hxx @@ -0,0 +1,98 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_REGISTRY_COMPONENT_DP_COMPBACKENDDB_HXX +#define INCLUDED_DESKTOP_SOURCE_DEPLOYMENT_REGISTRY_COMPONENT_DP_COMPBACKENDDB_HXX + +#include <rtl/ustring.hxx> +#include <rtl/string.hxx> +#include <vector> +#include <deque> +#include <dp_backenddb.hxx> + +namespace com::sun::star::uno { class XComponentContext; } + +namespace dp_registry { +namespace backend { +namespace component { + +/* The XML file stores the extensions which are currently registered. + They will be removed when they are revoked. + The format looks like this: + +<?xml version="1.0"?> +<component-backend-db xmlns="http://openoffice.org/extensionmanager/component-registry/2010"> + <component url="vnd.sun.star.expand:$UNO_USER_PACKAGES_CACHE/uno_packages/5CD5.tmp_/leaves1.oxt/extensionoptions.jar"> + <name>FileName</name> + <java-type-library>true</java-type-library> + <implementation-names> + <name>com.sun.star.comp.extensionoptions.OptionsEventHandler$_OptionsEventHandler</name> + ... + </implementation-names> + <singletons> + <item> + <key>com.sun.star.java.theJavaVirtualMachine</key> + <value>com.sun.star.java.JavaVirtualMachine</value> + </item> + ... + </singletons> + </component> + + <component ...> + ... +</component-backend-db> + */ +class ComponentBackendDb: public dp_registry::backend::BackendDb +{ +protected: + virtual OUString getDbNSName() override; + virtual OUString getNSPrefix() override; + virtual OUString getRootElementName() override; + virtual OUString getKeyElementName() override; + +public: + struct Data + { + Data(): javaTypeLibrary(false) {}; + + std::deque< OUString> implementationNames; + std::vector< std::pair< OUString, OUString> >singletons; + // map from singleton names to implementation names + bool javaTypeLibrary; + }; + +public: + + ComponentBackendDb( css::uno::Reference<css::uno::XComponentContext> const & xContext, + OUString const & url); + + void addEntry(OUString const & url, Data const & data); + + Data getEntry(OUString const & url); + + +}; + + +} +} +} +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/desktop/source/deployment/registry/component/dp_component.cxx b/desktop/source/deployment/registry/component/dp_component.cxx new file mode 100644 index 000000000..8cb39ce47 --- /dev/null +++ b/desktop/source/deployment/registry/component/dp_component.cxx @@ -0,0 +1,1706 @@ +/* -*- 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 <strings.hrc> +#include <dp_shared.hxx> +#include <dp_backend.h> +#include <dp_platform.hxx> +#include <dp_services.hxx> +#include <dp_ucb.h> +#include <rtl/string.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/ustrbuf.hxx> +#include <rtl/uri.hxx> +#include <sal/log.hxx> +#include <cppuhelper/exc_hlp.hxx> +#include <ucbhelper/content.hxx> +#include <comphelper/servicedecl.hxx> +#include <comphelper/sequence.hxx> +#include <xmlscript/xml_helper.hxx> +#include <svl/inettype.hxx> +#include <tools/diagnose_ex.h> +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/deployment/DeploymentException.hpp> +#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/registry/XSimpleRegistry.hpp> +#include <com/sun/star/registry/XImplementationRegistration.hpp> +#include <com/sun/star/loader/XImplementationLoader.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/ucb/NameClash.hpp> +#include <com/sun/star/util/theMacroExpander.hpp> +#include <algorithm> +#include <deque> +#include <memory> +#include <unordered_map> +#include <vector> +#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 { + +#define IMPLEMENTATION_NAME "com.sun.star.comp.deployment.component.PackageRegistryBackend" + +/** return a vector of bootstrap variables which have been provided + as command arguments. +*/ +std::vector<OUString> getCmdBootstrapVariables() +{ + std::vector<OUString> 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<XCommandEnvironment> 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<XComponentContext> 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<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + + Reference<registry::XSimpleRegistry> getRDB() const; + + public: + ComponentPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> 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<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + public: + ComponentsPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> 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<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + + public: + TypelibraryPackageImpl( + ::rtl::Reference<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> 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<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, OUString const & identifier, OUString const& rPlatform); + + private: + BackendImpl * getMyBackend() const; + + Reference<registry::XSimpleRegistry> impl_openRDB() const; + Reference<XInterface> impl_createInstance(OUString const& rService) const; + + // Package + virtual beans::Optional< beans::Ambiguous<sal_Bool> > isRegistered_( + ::osl::ResettableMutexGuard & guard, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + virtual void processPackage_( + ::osl::ResettableMutexGuard & guard, + bool registerPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + + private: + OUString const m_aPlatform; + }; + friend class OtherPlatformPackageImpl; + + std::deque<OUString> m_jar_typelibs; + std::deque<OUString> m_rdb_typelibs; + std::deque<OUString> m_components; + + enum RcItem { RCITEM_JAR_TYPELIB, RCITEM_RDB_TYPELIB, RCITEM_COMPONENTS }; + + std::deque<OUString> & 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<XInterface> > t_string2object; + t_string2object m_backendObjects; + + // PackageRegistryBackend + virtual Reference<deployment::XPackage> bindPackage_( + OUString const & url, OUString const & mediaType, + bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> const & xCmdEnv ) override; + + virtual void SAL_CALL disposing() override; + + const Reference<deployment::XPackageTypeInfo> m_xDynComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xJavaComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xPythonComponentTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xComponentsTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xRDBTypelibTypeInfo; + const Reference<deployment::XPackageTypeInfo> m_xJavaTypelibTypeInfo; + Sequence< Reference<deployment::XPackageTypeInfo> > 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<ComponentBackendDb> m_backendDb; + + void addDataToDb(OUString const & url, ComponentBackendDb::Data const & data); + ComponentBackendDb::Data readDataFromDb(OUString const & url); + void revokeEntryFromDb(OUString const & url); + + Reference<registry::XSimpleRegistry> m_xCommonRDB; + Reference<registry::XSimpleRegistry> m_xNativeRDB; + + void unorc_verify_init( Reference<XCommandEnvironment> const & xCmdEnv ); + void unorc_flush( Reference<XCommandEnvironment> const & xCmdEnv ); + + Reference<XInterface> getObject( OUString const & id ); + Reference<XInterface> insertObject( + OUString const & id, Reference<XInterface> const & xObject ); + void releaseObject( OUString const & id ); + + void addToUnoRc( RcItem kind, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + void removeFromUnoRc( RcItem kind, OUString const & url, + Reference<XCommandEnvironment> const & xCmdEnv ); + bool hasInUnoRc( RcItem kind, OUString const & url ); + + css::uno::Reference< css::uno::XComponentContext > getRootContext() const; + +public: + BackendImpl( Sequence<Any> const & args, + Reference<XComponentContext> const & xComponentContext ); + + // XPackageRegistry + virtual Sequence< Reference<deployment::XPackageTypeInfo> > 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<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> 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<registry::XSimpleRegistry> +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<BackendImpl *>(m_myBackend.get()); + if (nullptr == pBackend) + { + //Throws a DisposedException + check(); + //We should never get here... + throw RuntimeException( + "Failed to get the BackendImpl", + static_cast<OWeakObject*>(const_cast<ComponentPackageImpl *>(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<XCommandEnvironment>() ); + + PackageRegistryBackend::disposing(); + } + catch (const RuntimeException &) { + throw; + } + catch (const Exception &) { + Any exc( ::cppu::getCaughtException() ); + throw lang::WrappedTargetRuntimeException( + "caught unexpected exception while disposing...", + static_cast<OWeakObject *>(this), exc ); + } +} + + +void BackendImpl::initServiceRdbFiles() +{ + const Reference<XCommandEnvironment> 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" ? OUStringLiteral("common_.rdb") : OUStringLiteral("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<XCommandEnvironment>() ); + + + // 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<Any> const & args, + Reference<XComponentContext> 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<XCommandEnvironment> 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)); + } +} + +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<deployment::XPackageTypeInfo> > +BackendImpl::getSupportedPackageTypes() +{ + return m_typeInfos; +} + +void BackendImpl::packageRemoved(OUString const & url, OUString const & /*mediaType*/) +{ + if (m_backendDb) + m_backendDb->removeEntry(url); +} + +// PackageRegistryBackend + +Reference<deployment::XPackage> BackendImpl::bindPackage_( + OUString const & url, OUString const & mediaType_, + bool bRemoved, OUString const & identifier, + Reference<XCommandEnvironment> 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<OWeakObject *>(this), static_cast<sal_Int16>(-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<OWeakObject *>(this), + static_cast<sal_Int16>(-1) ); +} + + +void BackendImpl::unorc_verify_init( + Reference<XCommandEnvironment> 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/" <common-rdb>)? -- 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<XCommandEnvironment> 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<io::XInputStream> xData( + ::xmlscript::createInputStream( + reinterpret_cast<sal_Int8 const *>(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<io::XInputStream> xData( + ::xmlscript::createInputStream( + reinterpret_cast<sal_Int8 const *>(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<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + unorc_verify_init( xCmdEnv ); + std::deque<OUString> & 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<XCommandEnvironment> const & xCmdEnv ) +{ + const OUString rcterm( dp_misc::makeRcTerm(url_) ); + const ::osl::MutexGuard guard( getMutex() ); + unorc_verify_init( xCmdEnv ); + std::deque<OUString> & 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<OUString> 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<XInterface> 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<XInterface>(); + else + return iFind->second; +} + + +Reference<XInterface> BackendImpl::insertObject( + OUString const & id, Reference<XInterface> const & xObject ) +{ + const ::osl::MutexGuard guard( getMutex() ); + const std::pair<t_string2object::iterator, bool> insertion( + m_backendObjects.emplace( id, xObject ) ); + return insertion.first->second; +} + + +Reference<XComponentContext> raise_uno_process( + Reference<XComponentContext> const & xContext, + ::rtl::Reference<AbortChannel> 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<OUString> 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<OUString> 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<XComponentContext>( + 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<XComponentContext> const & xContext ) +{ + const Reference<loader::XImplementationLoader> 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<registry::XSimpleRegistry> 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<sal_Bool> > +BackendImpl::ComponentPackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> const & ) +{ + if (m_registered == Reg::Uninit) + { + m_registered = Reg::NotRegistered; + const Reference<registry::XSimpleRegistry> xRDB( getRDB() ); + if (xRDB.is()) + { + bool bAmbiguousComponentName = false; + // lookup rdb for location URL: + const Reference<registry::XRegistryKey> xRootKey( + xRDB->getRootKey() ); + const Reference<registry::XRegistryKey> xImplKey( + xRootKey->openKey( "IMPLEMENTATIONS" ) ); + Sequence<OUString> 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<registry::XRegistryKey> 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<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( + m_registered == Reg::Registered, bAmbiguous) ); +} + + +void BackendImpl::ComponentPackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> 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<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> 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<BackendImpl *>(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<OWeakObject*>(const_cast<TypelibraryPackageImpl *>(this))); + } + return pBackend; +} + +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::TypelibraryPackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + BackendImpl * that = getMyBackend(); + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true /* IsPresent */, + beans::Ambiguous<sal_Bool>( + 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<AbortChannel> const &, + Reference<XCommandEnvironment> 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<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> 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<BackendImpl *>(m_myBackend.get()); + if (nullptr == pBackend) + { + //Throws a DisposedException + check(); + //We should never get here... + throw RuntimeException("Failed to get the BackendImpl", + static_cast<OWeakObject*>(const_cast<OtherPlatformPackageImpl*>(this))); + } + return pBackend; +} + +Reference<registry::XSimpleRegistry> +BackendImpl::OtherPlatformPackageImpl::impl_openRDB() const +{ + OUString const aRDB(m_aPlatform + ".rdb"); + OUString const aRDBPath(makeURL(getMyBackend()->getCachePath(), aRDB)); + + Reference<registry::XSimpleRegistry> 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<XInterface> +BackendImpl::OtherPlatformPackageImpl::impl_createInstance(OUString const& rService) +const +{ + Reference<XComponentContext> const xContext(getMyBackend()->getComponentContext()); + OSL_ASSERT(xContext.is()); + Reference<XInterface> xService; + if (xContext.is()) + xService.set(xContext->getServiceManager()->createInstanceWithContext(rService, xContext)); + return xService; +} + +beans::Optional<beans::Ambiguous<sal_Bool> > +BackendImpl::OtherPlatformPackageImpl::isRegistered_( + ::osl::ResettableMutexGuard& /* guard */, + ::rtl::Reference<AbortChannel> const& /* abortChannel */, + Reference<XCommandEnvironment> const& /* xCmdEnv */ ) +{ + return beans::Optional<beans::Ambiguous<sal_Bool> >(true, + beans::Ambiguous<sal_Bool>(true, false)); +} + +void +BackendImpl::OtherPlatformPackageImpl::processPackage_( + ::osl::ResettableMutexGuard& /* guard */, + bool bRegisterPackage, + bool /* bStartup */, + ::rtl::Reference<AbortChannel> const& /* abortChannel */, + Reference<XCommandEnvironment> const& /* xCmdEnv */) +{ + OSL_PRECOND(!bRegisterPackage, "this class can only be used for removing packages!"); + + OUString const aURL(getURL()); + + Reference<registry::XSimpleRegistry> const xServicesRDB(impl_openRDB()); + Reference<registry::XImplementationRegistration> 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<BackendImpl *>(m_myBackend.get()); + if (nullptr == pBackend) + { + //Throws a DisposedException + check(); + //We should never get here... + throw RuntimeException("Failed to get the BackendImpl", + static_cast<OWeakObject*>(const_cast<ComponentsPackageImpl *>(this))); + } + return pBackend; +} + +beans::Optional< beans::Ambiguous<sal_Bool> > +BackendImpl::ComponentsPackageImpl::isRegistered_( + ::osl::ResettableMutexGuard &, + ::rtl::Reference<AbortChannel> const &, + Reference<XCommandEnvironment> const & ) +{ + return beans::Optional< beans::Ambiguous<sal_Bool> >( + true, + beans::Ambiguous<sal_Bool>( + getMyBackend()->hasInUnoRc(RCITEM_COMPONENTS, getURL()), false)); +} + +void BackendImpl::ComponentsPackageImpl::processPackage_( + ::osl::ResettableMutexGuard &, + bool doRegisterPackage, + bool startup, + ::rtl::Reference<AbortChannel> const & abortChannel, + Reference<XCommandEnvironment> 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<PackageRegistryBackend> const & myBackend, + OUString const & url, OUString const & name, + Reference<deployment::XPackageTypeInfo> const & xPackageType, + bool bRemoved, OUString const & identifier) + : Package( myBackend, url, name, name /* display-name */, + xPackageType, bRemoved, identifier) +{} + +} // anon namespace + +namespace sdecl = comphelper::service_decl; +sdecl::class_<BackendImpl, sdecl::with_args<true> > serviceBI; +sdecl::ServiceDecl const serviceDecl( + serviceBI, + IMPLEMENTATION_NAME, + BACKEND_SERVICE_NAME ); + +} // namespace dp_registry + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |