/* -*- 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 using namespace osl; using namespace com::sun::star; using namespace com::sun::star::uno; using namespace com::sun::star::lang; using namespace com::sun::star::loader; using namespace com::sun::star::registry; namespace cppu { namespace { class OFactoryComponentHelper : public cppu::BaseMutex , public WeakComponentImplHelper< XServiceInfo, XSingleServiceFactory, lang::XSingleComponentFactory, XUnloadingPreference> { public: OFactoryComponentHelper( const Reference & rServiceManager, OUString aImplementationName_, ComponentInstantiation pCreateFunction_, ComponentFactoryFunc fptr, const Sequence< OUString > * pServiceNames_, bool bOneInstance_ ) : WeakComponentImplHelper( m_aMutex ) , bOneInstance( bOneInstance_ ) , xSMgr( rServiceManager ) , pCreateFunction( pCreateFunction_ ) , m_fptr( fptr ) , aImplementationName(std::move( aImplementationName_ )) { if( pServiceNames_ ) aServiceNames = *pServiceNames_; } // XSingleServiceFactory Reference SAL_CALL createInstance() override; Reference SAL_CALL createInstanceWithArguments( const Sequence& Arguments ) override; // XSingleComponentFactory virtual Reference< XInterface > SAL_CALL createInstanceWithContext( Reference< XComponentContext > const & xContext ) override; virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( Sequence< Any > const & rArguments, Reference< XComponentContext > const & xContext ) override; // XServiceInfo OUString SAL_CALL getImplementationName() override; sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; Sequence< OUString > SAL_CALL getSupportedServiceNames() override; // XTypeProvider virtual Sequence< Type > SAL_CALL getTypes() override; // XUnloadingPreference virtual sal_Bool SAL_CALL releaseOnNotification() override; // WeakComponentImplHelper void SAL_CALL disposing() override; private: css::uno::Reference createInstanceWithArgumentsEveryTime( css::uno::Sequence const & rArguments, css::uno::Reference const & xContext); Reference xTheInstance; bool bOneInstance; protected: // needed for implementing XUnloadingPreference in inheriting classes bool isOneInstance() const {return bOneInstance;} bool isInstance() const {return xTheInstance.is();} /** * Create an instance specified by the factory. The one instance logic is implemented * in the createInstance and createInstanceWithArguments methods. * @return the newly created instance. Do not return a previous (one instance) instance. * @throw css::uno::Exception * @throw css::uno::RuntimeException */ virtual Reference createInstanceEveryTime( Reference< XComponentContext > const & xContext ); Reference xSMgr; ComponentInstantiation pCreateFunction; ComponentFactoryFunc m_fptr; Sequence< OUString > aServiceNames; OUString aImplementationName; }; } // XTypeProvider Sequence< Type > OFactoryComponentHelper::getTypes() { Type ar[ 4 ]; ar[ 0 ] = cppu::UnoType::get(); ar[ 1 ] = cppu::UnoType::get(); ar[ 2 ] = cppu::UnoType::get(); if (m_fptr) ar[ 3 ] = cppu::UnoType::get(); return Sequence< Type >( ar, m_fptr ? 4 : 3 ); } // OFactoryComponentHelper Reference OFactoryComponentHelper::createInstanceEveryTime( Reference< XComponentContext > const & xContext ) { if (m_fptr) { return (*m_fptr)( xContext ); } if( pCreateFunction ) { if (xContext.is()) { Reference< lang::XMultiServiceFactory > xContextMgr( xContext->getServiceManager(), UNO_QUERY ); if (xContextMgr.is()) return (*pCreateFunction)( xContextMgr ); } return (*pCreateFunction)( xSMgr ); } return Reference< XInterface >(); } // XSingleServiceFactory Reference OFactoryComponentHelper::createInstance() { if( bOneInstance ) { if( !xTheInstance.is() ) { MutexGuard aGuard( m_aMutex ); if( !xTheInstance.is() ) xTheInstance = createInstanceEveryTime( Reference< XComponentContext >() ); } return xTheInstance; } return createInstanceEveryTime( Reference< XComponentContext >() ); } Reference OFactoryComponentHelper::createInstanceWithArguments( const Sequence& Arguments ) { if( bOneInstance ) { if( !xTheInstance.is() ) { MutexGuard aGuard( m_aMutex ); // OSL_ENSURE( !xTheInstance.is(), "### arguments will be ignored!" ); if( !xTheInstance.is() ) xTheInstance = createInstanceWithArgumentsEveryTime( Arguments, Reference< XComponentContext >() ); } return xTheInstance; } return createInstanceWithArgumentsEveryTime( Arguments, Reference< XComponentContext >() ); } // XSingleComponentFactory Reference< XInterface > OFactoryComponentHelper::createInstanceWithContext( Reference< XComponentContext > const & xContext ) { if( bOneInstance ) { if( !xTheInstance.is() ) { MutexGuard aGuard( m_aMutex ); // OSL_ENSURE( !xTheInstance.is(), "### context will be ignored!" ); if( !xTheInstance.is() ) xTheInstance = createInstanceEveryTime( xContext ); } return xTheInstance; } return createInstanceEveryTime( xContext ); } Reference< XInterface > OFactoryComponentHelper::createInstanceWithArgumentsAndContext( Sequence< Any > const & rArguments, Reference< XComponentContext > const & xContext ) { if( bOneInstance ) { if( !xTheInstance.is() ) { MutexGuard aGuard( m_aMutex ); // OSL_ENSURE( !xTheInstance.is(), "### context and arguments will be ignored!" ); if( !xTheInstance.is() ) xTheInstance = createInstanceWithArgumentsEveryTime( rArguments, xContext ); } return xTheInstance; } return createInstanceWithArgumentsEveryTime( rArguments, xContext ); } css::uno::Reference OFactoryComponentHelper::createInstanceWithArgumentsEveryTime( css::uno::Sequence const & rArguments, css::uno::Reference const & xContext) { Reference< XInterface > xRet( createInstanceEveryTime( xContext ) ); Reference< lang::XInitialization > xInit( xRet, UNO_QUERY ); // always call initialize, even if there are no arguments. #i63511# if (xInit.is()) { xInit->initialize( rArguments ); } else { if ( rArguments.hasElements() ) { // dispose the here created UNO object before throwing out exception // to avoid risk of memory leaks #i113722# Reference xComp( xRet, UNO_QUERY ); if (xComp.is()) xComp->dispose(); throw lang::IllegalArgumentException( "cannot pass arguments to component => no XInitialization implemented!", Reference< XInterface >(), 0 ); } } return xRet; } // WeakComponentImplHelper void OFactoryComponentHelper::disposing() { Reference x; { // do not delete in the guard section MutexGuard aGuard( m_aMutex ); x = xTheInstance; xTheInstance.clear(); } // if it is a component call dispose at the component Reference xComp( x, UNO_QUERY ); if( xComp.is() ) xComp->dispose(); } // XServiceInfo OUString OFactoryComponentHelper::getImplementationName() { return aImplementationName; } // XServiceInfo sal_Bool OFactoryComponentHelper::supportsService( const OUString& ServiceName ) { return cppu::supportsService(this, ServiceName); } // XServiceInfo Sequence< OUString > OFactoryComponentHelper::getSupportedServiceNames() { return aServiceNames; } // XUnloadingPreference // This class is used for single factories, component factories and // one-instance factories. Depending on the usage this function has // to return different values. // one-instance factory: sal_False // single factory: sal_True // component factory: sal_True sal_Bool SAL_CALL OFactoryComponentHelper::releaseOnNotification() { if( bOneInstance) return false; return true; } namespace { class ORegistryFactoryHelper : public OFactoryComponentHelper, public OPropertySetHelper { public: ORegistryFactoryHelper( const Reference & rServiceManager, const OUString & rImplementationName_, const Reference & xImplementationKey_, bool bOneInstance_ ) : OFactoryComponentHelper( rServiceManager, rImplementationName_, nullptr, nullptr, nullptr, bOneInstance_ ), OPropertySetHelper( WeakComponentImplHelper::rBHelper ), xImplementationKey( xImplementationKey_ ) {} // XInterface virtual Any SAL_CALL queryInterface( Type const & type ) override; virtual void SAL_CALL acquire() noexcept override; virtual void SAL_CALL release() noexcept override; // XTypeProvider virtual Sequence< Type > SAL_CALL getTypes() override; // XPropertySet virtual Reference< beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override; // OPropertySetHelper virtual IPropertyArrayHelper & SAL_CALL getInfoHelper() override; virtual sal_Bool SAL_CALL convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, Any const & rValue ) override; virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, Any const & rValue ) override; using OPropertySetHelper::getFastPropertyValue; virtual void SAL_CALL getFastPropertyValue( Any & rValue, sal_Int32 nHandle ) const override; // OFactoryComponentHelper Reference createInstanceEveryTime( Reference< XComponentContext > const & xContext ) override; // XSingleServiceFactory Reference SAL_CALL createInstanceWithArguments(const Sequence& Arguments) override; // XSingleComponentFactory Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( Sequence< Any > const & rArguments, Reference< XComponentContext > const & xContext ) override; // XServiceInfo Sequence< OUString > SAL_CALL getSupportedServiceNames() override; // XUnloadingPreference sal_Bool SAL_CALL releaseOnNotification() override; private: /// @throws css::uno::Exception /// @throws css::uno::RuntimeException Reference< XInterface > createModuleFactory(); /** The registry key of the implementation section */ Reference xImplementationKey; /** The factory created with the loader. */ Reference xModuleFactory; Reference xModuleFactoryDepr; Reference< beans::XPropertySetInfo > m_xInfo; std::unique_ptr< IPropertyArrayHelper > m_property_array_helper; protected: using OPropertySetHelper::getTypes; }; } // XInterface Any SAL_CALL ORegistryFactoryHelper::queryInterface( Type const & type ) { Any ret( OFactoryComponentHelper::queryInterface( type ) ); if (ret.hasValue()) return ret; return OPropertySetHelper::queryInterface( type ); } void ORegistryFactoryHelper::acquire() noexcept { OFactoryComponentHelper::acquire(); } void ORegistryFactoryHelper::release() noexcept { OFactoryComponentHelper::release(); } // XTypeProvider Sequence< Type > ORegistryFactoryHelper::getTypes() { Sequence< Type > types( OFactoryComponentHelper::getTypes() ); sal_Int32 pos = types.getLength(); types.realloc( pos + 3 ); Type * p = types.getArray(); p[ pos++ ] = cppu::UnoType::get(); p[ pos++ ] = cppu::UnoType::get(); p[ pos++ ] = cppu::UnoType::get(); return types; } // XPropertySet Reference< beans::XPropertySetInfo > ORegistryFactoryHelper::getPropertySetInfo() { ::osl::MutexGuard guard( m_aMutex ); if (! m_xInfo.is()) m_xInfo = createPropertySetInfo( getInfoHelper() ); return m_xInfo; } // OPropertySetHelper IPropertyArrayHelper & ORegistryFactoryHelper::getInfoHelper() { ::osl::MutexGuard guard( m_aMutex ); if (m_property_array_helper == nullptr) { beans::Property prop( "ImplementationKey" /* name */, 0 /* handle */, cppu::UnoType::get(), beans::PropertyAttribute::READONLY | beans::PropertyAttribute::OPTIONAL ); m_property_array_helper.reset( new ::cppu::OPropertyArrayHelper( &prop, 1 ) ); } return *m_property_array_helper; } sal_Bool ORegistryFactoryHelper::convertFastPropertyValue( Any &, Any &, sal_Int32, Any const & ) { OSL_FAIL( "unexpected!" ); return false; } void ORegistryFactoryHelper::setFastPropertyValue_NoBroadcast( sal_Int32, Any const & ) { throw beans::PropertyVetoException( "unexpected: only readonly properties!", static_cast< OWeakObject * >(this) ); } void ORegistryFactoryHelper::getFastPropertyValue( Any & rValue, sal_Int32 nHandle ) const { if (nHandle == 0) { rValue <<= xImplementationKey; } else { rValue.clear(); throw beans::UnknownPropertyException( "unknown property!", static_cast< OWeakObject * >( const_cast< ORegistryFactoryHelper * >(this) ) ); } } Reference ORegistryFactoryHelper::createInstanceEveryTime( Reference< XComponentContext > const & xContext ) { if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) { Reference< XInterface > x( createModuleFactory() ); if (x.is()) { MutexGuard aGuard( m_aMutex ); if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) { xModuleFactory.set( x, UNO_QUERY ); xModuleFactoryDepr.set( x, UNO_QUERY ); } } } if( xModuleFactory.is() ) { return xModuleFactory->createInstanceWithContext( xContext ); } if( xModuleFactoryDepr.is() ) { return xModuleFactoryDepr->createInstance(); } return Reference(); } Reference SAL_CALL ORegistryFactoryHelper::createInstanceWithArguments( const Sequence& Arguments ) { if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) { Reference< XInterface > x( createModuleFactory() ); if (x.is()) { MutexGuard aGuard( m_aMutex ); if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) { xModuleFactory.set( x, UNO_QUERY ); xModuleFactoryDepr.set( x, UNO_QUERY ); } } } if( xModuleFactoryDepr.is() ) { return xModuleFactoryDepr->createInstanceWithArguments( Arguments ); } if( xModuleFactory.is() ) { SAL_INFO("cppuhelper", "no context ORegistryFactoryHelper::createInstanceWithArgumentsAndContext()!"); return xModuleFactory->createInstanceWithArgumentsAndContext( Arguments, Reference< XComponentContext >() ); } return Reference(); } Reference< XInterface > ORegistryFactoryHelper::createInstanceWithArgumentsAndContext( Sequence< Any > const & rArguments, Reference< XComponentContext > const & xContext ) { if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) { Reference< XInterface > x( createModuleFactory() ); if (x.is()) { MutexGuard aGuard( m_aMutex ); if( !xModuleFactory.is() && !xModuleFactoryDepr.is() ) { xModuleFactory.set( x, UNO_QUERY ); xModuleFactoryDepr.set( x, UNO_QUERY ); } } } if( xModuleFactory.is() ) { return xModuleFactory->createInstanceWithArgumentsAndContext( rArguments, xContext ); } if( xModuleFactoryDepr.is() ) { SAL_INFO_IF(xContext.is(), "cppuhelper", "ignoring context calling ORegistryFactoryHelper::createInstanceWithArgumentsAndContext()!"); return xModuleFactoryDepr->createInstanceWithArguments( rArguments ); } return Reference(); } Reference< XInterface > ORegistryFactoryHelper::createModuleFactory() { OUString aActivatorUrl; OUString aActivatorName; OUString aLocation; Reference xActivatorKey = xImplementationKey->openKey( "/UNO/ACTIVATOR" ); if( xActivatorKey.is() && xActivatorKey->getValueType() == RegistryValueType_ASCII ) { aActivatorUrl = xActivatorKey->getAsciiValue(); aActivatorName = o3tl::getToken(aActivatorUrl, 0, ':'); Reference xLocationKey = xImplementationKey->openKey( "/UNO/LOCATION" ); if( xLocationKey.is() && xLocationKey->getValueType() == RegistryValueType_ASCII ) aLocation = xLocationKey->getAsciiValue(); } else { // old style"url" // the location of the program code of the implementation Reference xLocationKey = xImplementationKey->openKey( "/UNO/URL" ); // is the key of the right type ? if( xLocationKey.is() && xLocationKey->getValueType() == RegistryValueType_ASCII ) { // one implementation found -> try to activate aLocation = xLocationKey->getAsciiValue(); // search protocol delimiter sal_Int32 nPos = aLocation.indexOf("://"); if( nPos != -1 ) { aActivatorName = aLocation.subView( 0, nPos ); if( aActivatorName == u"java" ) aActivatorName = u"com.sun.star.loader.Java"_ustr; else if( aActivatorName == u"module" ) aActivatorName = u"com.sun.star.loader.SharedLibrary"_ustr; aLocation = aLocation.copy( nPos + 3 ); } } } Reference< XInterface > xFactory; if( !aActivatorName.isEmpty() ) { Reference x = xSMgr->createInstance( aActivatorName ); Reference xLoader( x, UNO_QUERY ); if (xLoader.is()) { xFactory = xLoader->activate( aImplementationName, aActivatorUrl, aLocation, xImplementationKey ); } } return xFactory; } // XServiceInfo Sequence< OUString > ORegistryFactoryHelper::getSupportedServiceNames() { MutexGuard aGuard( m_aMutex ); if( !aServiceNames.hasElements() ) { // not yet loaded try { Reference xKey = xImplementationKey->openKey( "UNO/SERVICES" ); if (xKey.is()) { // length of prefix. +1 for the '/' at the end sal_Int32 nPrefixLen = xKey->getKeyName().getLength() + 1; // Full qualified names like "IMPLEMENTATIONS/TEST/UNO/SERVICES/com.sun.star..." Sequence seqKeys = xKey->getKeyNames(); for( OUString & key : asNonConstRange(seqKeys) ) key = key.copy(nPrefixLen); aServiceNames = seqKeys; } } catch (InvalidRegistryException &) { } } return aServiceNames; } sal_Bool SAL_CALL ORegistryFactoryHelper::releaseOnNotification() { bool retVal= true; if( isOneInstance() && isInstance()) { retVal= false; } else if( ! isOneInstance()) { // try to delegate if( xModuleFactory.is()) { Reference xunloading( xModuleFactory, UNO_QUERY); if( xunloading.is()) retVal= xunloading->releaseOnNotification(); } else if( xModuleFactoryDepr.is()) { Reference xunloading( xModuleFactoryDepr, UNO_QUERY); if( xunloading.is()) retVal= xunloading->releaseOnNotification(); } } return retVal; } namespace { class OFactoryProxyHelper : public WeakImplHelper< XServiceInfo, XSingleServiceFactory, XUnloadingPreference > { Reference xFactory; public: explicit OFactoryProxyHelper( const Reference & rFactory ) : xFactory( rFactory ) {} // XSingleServiceFactory Reference SAL_CALL createInstance() override; Reference SAL_CALL createInstanceWithArguments(const Sequence& Arguments) override; // XServiceInfo OUString SAL_CALL getImplementationName() override; sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; Sequence< OUString > SAL_CALL getSupportedServiceNames() override; //XUnloadingPreference sal_Bool SAL_CALL releaseOnNotification() override; }; } // XSingleServiceFactory Reference OFactoryProxyHelper::createInstance() { return xFactory->createInstance(); } // XSingleServiceFactory Reference OFactoryProxyHelper::createInstanceWithArguments ( const Sequence& Arguments ) { return xFactory->createInstanceWithArguments( Arguments ); } // XServiceInfo OUString OFactoryProxyHelper::getImplementationName() { Reference xInfo( xFactory, UNO_QUERY ); if( xInfo.is() ) return xInfo->getImplementationName(); return OUString(); } // XServiceInfo sal_Bool OFactoryProxyHelper::supportsService(const OUString& ServiceName) { return cppu::supportsService(this, ServiceName); } // XServiceInfo Sequence< OUString > OFactoryProxyHelper::getSupportedServiceNames() { Reference xInfo( xFactory, UNO_QUERY ); if( xInfo.is() ) return xInfo->getSupportedServiceNames(); return Sequence< OUString >(); } sal_Bool SAL_CALL OFactoryProxyHelper::releaseOnNotification() { Reference pref( xFactory, UNO_QUERY); if( pref.is()) return pref->releaseOnNotification(); return true; } // global function Reference SAL_CALL createSingleFactory( const Reference & rServiceManager, const OUString & rImplementationName, ComponentInstantiation pCreateFunction, const Sequence< OUString > & rServiceNames, rtl_ModuleCount * ) { return new OFactoryComponentHelper( rServiceManager, rImplementationName, pCreateFunction, nullptr, &rServiceNames, false ); } // global function Reference SAL_CALL createFactoryProxy( SAL_UNUSED_PARAMETER const Reference &, const Reference & rFactory ) { return new OFactoryProxyHelper( rFactory ); } // global function Reference SAL_CALL createOneInstanceFactory( const Reference & rServiceManager, const OUString & rImplementationName, ComponentInstantiation pCreateFunction, const Sequence< OUString > & rServiceNames, rtl_ModuleCount * ) { return new OFactoryComponentHelper( rServiceManager, rImplementationName, pCreateFunction, nullptr, &rServiceNames, true ); } // global function Reference SAL_CALL createSingleRegistryFactory( const Reference & rServiceManager, const OUString & rImplementationName, const Reference & rImplementationKey ) { return new ORegistryFactoryHelper( rServiceManager, rImplementationName, rImplementationKey, false ); } // global function Reference SAL_CALL createOneInstanceRegistryFactory( const Reference & rServiceManager, const OUString & rImplementationName, const Reference & rImplementationKey ) { return new ORegistryFactoryHelper( rServiceManager, rImplementationName, rImplementationKey, true ); } Reference< lang::XSingleComponentFactory > SAL_CALL createSingleComponentFactory( ComponentFactoryFunc fptr, OUString const & rImplementationName, Sequence< OUString > const & rServiceNames, rtl_ModuleCount *) { return new OFactoryComponentHelper( Reference< XMultiServiceFactory >(), rImplementationName, nullptr, fptr, &rServiceNames, false ); } Reference< lang::XSingleComponentFactory > SAL_CALL createOneInstanceComponentFactory( ComponentFactoryFunc fptr, OUString const & rImplementationName, Sequence< OUString > const & rServiceNames, rtl_ModuleCount *) { return new OFactoryComponentHelper( Reference< XMultiServiceFactory >(), rImplementationName, nullptr, fptr, &rServiceNames, true ); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */