diff options
Diffstat (limited to 'stoc/source/servicemanager/servicemanager.cxx')
-rw-r--r-- | stoc/source/servicemanager/servicemanager.cxx | 1476 |
1 files changed, 1476 insertions, 0 deletions
diff --git a/stoc/source/servicemanager/servicemanager.cxx b/stoc/source/servicemanager/servicemanager.cxx new file mode 100644 index 0000000000..c61e23cf85 --- /dev/null +++ b/stoc/source/servicemanager/servicemanager.cxx @@ -0,0 +1,1476 @@ +/* -*- 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 <sal/config.h> + +#include <o3tl/any.hxx> +#include <osl/mutex.hxx> +#include <osl/diagnose.h> +#include <sal/log.hxx> + +#include <cppuhelper/basemutex.hxx> +#include <cppuhelper/factory.hxx> +#include <cppuhelper/weakref.hxx> +#include <cppuhelper/implbase.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <comphelper/sequence.hxx> + +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/lang/XMultiComponentFactory.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XSingleServiceFactory.hpp> +#include <com/sun/star/lang/XSingleComponentFactory.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XEventListener.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <com/sun/star/registry/XRegistryKey.hpp> +#include <com/sun/star/registry/XSimpleRegistry.hpp> +#include <com/sun/star/container/XSet.hpp> +#include <com/sun/star/container/XElementAccess.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/container/XContentEnumerationAccess.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> + +#include <iterator> +#include <mutex> +#include <string_view> +#include <unordered_map> +#include <unordered_set> +#include <utility> + +using namespace com::sun::star; +using namespace css::uno; +using namespace css::beans; +using namespace css::registry; +using namespace css::lang; +using namespace css::container; +using namespace cppu; +using namespace osl; + +namespace { + +Sequence< OUString > retrieveAsciiValueList( + const Reference< XSimpleRegistry > &xReg, const OUString &keyName ) +{ + Reference< XEnumerationAccess > xAccess( xReg, UNO_QUERY ); + Sequence< OUString > seq; + if( xAccess.is() ) + { + Reference< XEnumeration > xEnum = xAccess->createEnumeration(); + while( xEnum.is() && xEnum->hasMoreElements() ) + { + Reference< XSimpleRegistry > xTempReg; + xEnum->nextElement() >>= xTempReg; + if( xTempReg.is() ) + { + const Sequence< OUString > seq2 = retrieveAsciiValueList( xTempReg, keyName ); + + if( seq2.hasElements() ) + { + sal_Int32 n1Len = seq.getLength(); + sal_Int32 n2Len = seq2.getLength(); + + seq.realloc( n1Len + n2Len ); + std::copy(seq2.begin(), seq2.end(), std::next(seq.getArray(), n1Len)); + } + } + } + } + else if( xReg.is () ) + { + try + { + Reference< XRegistryKey > rRootKey = xReg->getRootKey(); + if( rRootKey.is() ) + { + Reference<XRegistryKey > xKey = rRootKey->openKey(keyName); + if( xKey.is() ) + { + seq = xKey->getAsciiListValue(); + } + } + } + catch( InvalidRegistryException & ) + { + } + catch (InvalidValueException &) + { + } + } + return seq; +} + +/***************************************************************************** + Enumeration by ServiceName +*****************************************************************************/ + +typedef std::unordered_set< Reference<XInterface > > HashSet_Ref; + + +class ServiceEnumeration_Impl : public WeakImplHelper< XEnumeration > +{ +public: + explicit ServiceEnumeration_Impl( const Sequence< Reference<XInterface > > & rFactories ) + : aFactories( rFactories ) + , nIt( 0 ) + {} + + // XEnumeration + sal_Bool SAL_CALL hasMoreElements() override; + Any SAL_CALL nextElement() override; +private: + std::mutex aMutex; + Sequence< Reference<XInterface > > aFactories; + sal_Int32 nIt; +}; + +// XEnumeration +sal_Bool ServiceEnumeration_Impl::hasMoreElements() +{ + std::scoped_lock aGuard( aMutex ); + return nIt != aFactories.getLength(); +} + +// XEnumeration +Any ServiceEnumeration_Impl::nextElement() +{ + std::scoped_lock aGuard( aMutex ); + if( nIt == aFactories.getLength() ) + throw NoSuchElementException("no more elements"); + + return Any( &aFactories.getConstArray()[nIt++], cppu::UnoType<XInterface>::get()); +} + + +class PropertySetInfo_Impl : public WeakImplHelper< beans::XPropertySetInfo > +{ + Sequence< beans::Property > m_properties; + +public: + explicit PropertySetInfo_Impl( Sequence< beans::Property > const & properties ) + : m_properties( properties ) + {} + + // XPropertySetInfo impl + virtual Sequence< beans::Property > SAL_CALL getProperties() override; + virtual beans::Property SAL_CALL getPropertyByName( OUString const & name ) override; + virtual sal_Bool SAL_CALL hasPropertyByName( OUString const & name ) override; +}; + +Sequence< beans::Property > PropertySetInfo_Impl::getProperties() +{ + return m_properties; +} + +beans::Property PropertySetInfo_Impl::getPropertyByName( OUString const & name ) +{ + beans::Property const * p = m_properties.getConstArray(); + for ( sal_Int32 nPos = m_properties.getLength(); nPos--; ) + { + if (p[ nPos ].Name == name) + return p[ nPos ]; + } + throw beans::UnknownPropertyException( + "unknown property: " + name ); +} + +sal_Bool PropertySetInfo_Impl::hasPropertyByName( OUString const & name ) +{ + return std::any_of(std::cbegin(m_properties), std::cend(m_properties), + [&name](const beans::Property& rProp) { return rProp.Name == name; }); +} + + +/***************************************************************************** + Enumeration by implementation +*****************************************************************************/ +class ImplementationEnumeration_Impl : public WeakImplHelper< XEnumeration > +{ +public: + explicit ImplementationEnumeration_Impl( HashSet_Ref xImplementationMap ) + : aImplementationMap(std::move( xImplementationMap )) + , aIt( aImplementationMap.begin() ) + {} + + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements() override; + virtual Any SAL_CALL nextElement() override; + +private: + std::mutex aMutex; + HashSet_Ref aImplementationMap; + HashSet_Ref::iterator aIt; +}; + +// XEnumeration +sal_Bool ImplementationEnumeration_Impl::hasMoreElements() +{ + std::scoped_lock aGuard( aMutex ); + return aIt != aImplementationMap.end(); +} + +// XEnumeration +Any ImplementationEnumeration_Impl::nextElement() +{ + std::scoped_lock aGuard( aMutex ); + if( aIt == aImplementationMap.end() ) + throw NoSuchElementException("no more elements"); + + Any ret( &(*aIt), cppu::UnoType<XInterface>::get()); + ++aIt; + return ret; +} + +/***************************************************************************** + Hash tables +*****************************************************************************/ +typedef std::unordered_set +< + OUString +> HashSet_OWString; + +typedef std::unordered_multimap +< + OUString, + Reference<XInterface > +> HashMultimap_OWString_Interface; + +typedef std::unordered_map +< + OUString, + Reference<XInterface > +> HashMap_OWString_Interface; + +/***************************************************************************** + class OServiceManager_Listener +*****************************************************************************/ +class OServiceManager_Listener : public WeakImplHelper< XEventListener > +{ +private: + WeakReference<XSet > xSMgr; + +public: + explicit OServiceManager_Listener( const Reference<XSet > & rSMgr ) + : xSMgr( rSMgr ) + {} + + // XEventListener + virtual void SAL_CALL disposing(const EventObject & rEvt ) override; +}; + +void OServiceManager_Listener::disposing(const EventObject & rEvt ) +{ + Reference<XSet > x( xSMgr ); + if( !x.is() ) + return; + + try + { + x->remove( Any( &rEvt.Source, cppu::UnoType<XInterface>::get()) ); + } + catch( const IllegalArgumentException & ) + { + OSL_FAIL( "IllegalArgumentException caught" ); + } + catch( const NoSuchElementException & ) + { + OSL_FAIL( "NoSuchElementException caught" ); + } +} + + +/***************************************************************************** + class OServiceManager +*****************************************************************************/ + +typedef WeakComponentImplHelper< + lang::XMultiServiceFactory, lang::XMultiComponentFactory, lang::XServiceInfo, + lang::XInitialization, + container::XSet, container::XContentEnumerationAccess, + beans::XPropertySet > t_OServiceManager_impl; + +class OServiceManager + : public cppu::BaseMutex + , public t_OServiceManager_impl +{ +public: + explicit OServiceManager( Reference< XComponentContext > const & xContext ); + + // XInitialization + void SAL_CALL initialize( Sequence< Any > const & args ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XMultiComponentFactory + virtual Reference< XInterface > SAL_CALL createInstanceWithContext( + OUString const & rServiceSpecifier, Reference< XComponentContext > const & xContext ) override; + virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( + OUString const & rServiceSpecifier, + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) override; +// virtual Sequence< OUString > SAL_CALL getAvailableServiceNames() +// throw (RuntimeException); + + // XMultiServiceFactory + virtual Sequence< OUString > SAL_CALL getAvailableServiceNames() override; + virtual Reference<XInterface > SAL_CALL createInstance(const OUString &) override; + virtual Reference<XInterface > SAL_CALL createInstanceWithArguments(const OUString &, const Sequence<Any >& Arguments) override; + + // The same as the getAvailableServiceNames, but only unique names + Sequence< OUString > getUniqueAvailableServiceNames( + HashSet_OWString & aNameSet ); + + // XElementAccess + virtual Type SAL_CALL getElementType() override; + virtual sal_Bool SAL_CALL hasElements() override; + + // XEnumerationAccess + virtual Reference<XEnumeration > SAL_CALL createEnumeration() override; + + // XSet + virtual sal_Bool SAL_CALL has( const Any & Element ) override; + virtual void SAL_CALL insert( const Any & Element ) override; + virtual void SAL_CALL remove( const Any & Element ) override; + + // XContentEnumerationAccess + //Sequence< OUString > getAvailableServiceNames() throw( (Exception) ); + virtual Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override; + + // XComponent + virtual void SAL_CALL dispose() override; + + // XPropertySet + Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + void SAL_CALL setPropertyValue(const OUString& PropertyName, const Any& aValue) override; + Any SAL_CALL getPropertyValue(const OUString& PropertyName) override; + void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override; + void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override; + void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override; + void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override; + +protected: + bool is_disposed() const; + void check_undisposed() const; + virtual void SAL_CALL disposing() override; + + bool haveFactoryWithThisImplementation(const OUString& aImplName); + + virtual Sequence< Reference< XInterface > > queryServiceFactories( + const OUString& aServiceName, Reference< XComponentContext > const & xContext ); + + Reference< XComponentContext > m_xContext; + + Reference< beans::XPropertySetInfo > m_xPropertyInfo; + + // factories which have been loaded and not inserted( by XSet::insert) + // are remembered by this set. + HashSet_Ref m_SetLoadedFactories; +private: + + Reference<XEventListener > getFactoryListener(); + + + HashMultimap_OWString_Interface m_ServiceMap; + HashSet_Ref m_ImplementationMap; + HashMap_OWString_Interface m_ImplementationNameMap; + Reference<XEventListener > xFactoryListener; + bool m_bInDisposing; +}; + + +bool OServiceManager::is_disposed() const +{ + // ought to be guarded by m_mutex: + return (m_bInDisposing || rBHelper.bDisposed); +} + + +void OServiceManager::check_undisposed() const +{ + if (is_disposed()) + { + throw lang::DisposedException( + "service manager instance has already been disposed!", + const_cast<OServiceManager *>(this)->getXWeak() ); + } +} + + +typedef WeakComponentImplHelper< + lang::XMultiServiceFactory, lang::XMultiComponentFactory, lang::XServiceInfo, + container::XSet, container::XContentEnumerationAccess, + beans::XPropertySet > t_OServiceManagerWrapper_impl; + +class OServiceManagerWrapper : public cppu::BaseMutex, public t_OServiceManagerWrapper_impl +{ + Reference< XComponentContext > m_xContext; + Reference< XMultiComponentFactory > m_root; + Reference< XMultiComponentFactory > const & getRoot() const + { + if (! m_root.is()) + { + throw lang::DisposedException( + "service manager instance has already been disposed!" ); + } + return m_root; + } + +protected: + virtual void SAL_CALL disposing() override; + +public: + explicit OServiceManagerWrapper( + Reference< XComponentContext > const & xContext ); + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override + { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->getImplementationName(); } + virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override + { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->supportsService( ServiceName ); } + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override + { return Reference< XServiceInfo >(getRoot(), UNO_QUERY_THROW)->getSupportedServiceNames(); } + + // XMultiComponentFactory + virtual Reference< XInterface > SAL_CALL createInstanceWithContext( + OUString const & rServiceSpecifier, Reference< XComponentContext > const & xContext ) override + { return getRoot()->createInstanceWithContext( rServiceSpecifier, xContext ); } + virtual Reference< XInterface > SAL_CALL createInstanceWithArgumentsAndContext( + OUString const & rServiceSpecifier, + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) override + { return getRoot()->createInstanceWithArgumentsAndContext( rServiceSpecifier, rArguments, xContext ); } +// virtual Sequence< OUString > SAL_CALL getAvailableServiceNames() +// throw (RuntimeException); + + // XMultiServiceFactory + virtual Sequence< OUString > SAL_CALL getAvailableServiceNames() override + { return getRoot()->getAvailableServiceNames(); } + virtual Reference<XInterface > SAL_CALL createInstance(const OUString & name) override + { return getRoot()->createInstanceWithContext( name, m_xContext ); } + virtual Reference<XInterface > SAL_CALL createInstanceWithArguments(const OUString & name, const Sequence<Any >& Arguments) override + { return getRoot()->createInstanceWithArgumentsAndContext( name, Arguments, m_xContext ); } + + // XElementAccess + virtual Type SAL_CALL getElementType() override + { return Reference< XElementAccess >(getRoot(), UNO_QUERY_THROW)->getElementType(); } + virtual sal_Bool SAL_CALL hasElements() override + { return Reference< XElementAccess >(getRoot(), UNO_QUERY_THROW)->hasElements(); } + + // XEnumerationAccess + virtual Reference<XEnumeration > SAL_CALL createEnumeration() override + { return Reference< XEnumerationAccess >(getRoot(), UNO_QUERY_THROW)->createEnumeration(); } + + // XSet + virtual sal_Bool SAL_CALL has( const Any & Element ) override + { return Reference< XSet >(getRoot(), UNO_QUERY_THROW)->has( Element ); } + virtual void SAL_CALL insert( const Any & Element ) override + { Reference< XSet >(getRoot(), UNO_QUERY_THROW)->insert( Element ); } + virtual void SAL_CALL remove( const Any & Element ) override + { Reference< XSet >(getRoot(), UNO_QUERY_THROW)->remove( Element ); } + + // XContentEnumerationAccess + //Sequence< OUString > getAvailableServiceNames() throw( (Exception) ); + virtual Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override + { return Reference< XContentEnumerationAccess >(getRoot(), UNO_QUERY_THROW)->createContentEnumeration( aServiceName ); } + + // XPropertySet + Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override + { return Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->getPropertySetInfo(); } + + void SAL_CALL setPropertyValue(const OUString& PropertyName, const Any& aValue) override; + Any SAL_CALL getPropertyValue(const OUString& PropertyName) override; + + void SAL_CALL addPropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override + { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->addPropertyChangeListener( PropertyName, aListener ); } + void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference<XPropertyChangeListener >& aListener) override + { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->removePropertyChangeListener( PropertyName, aListener ); } + void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override + { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->addVetoableChangeListener( PropertyName, aListener ); } + void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference<XVetoableChangeListener >& aListener) override + { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->removeVetoableChangeListener( PropertyName, aListener ); } +}; + +void SAL_CALL OServiceManagerWrapper::setPropertyValue( + const OUString& PropertyName, const Any& aValue ) +{ + if ( PropertyName == "DefaultContext" ) + { + Reference< XComponentContext > xContext; + if (!(aValue >>= xContext)) + { + throw IllegalArgumentException( + "no XComponentContext given!", + getXWeak(), 1 ); + } + + MutexGuard aGuard( m_aMutex ); + m_xContext = xContext; + + } + else + { + Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->setPropertyValue( PropertyName, aValue ); + } +} + +Any SAL_CALL OServiceManagerWrapper::getPropertyValue( + const OUString& PropertyName ) +{ + if ( PropertyName == "DefaultContext" ) + { + MutexGuard aGuard( m_aMutex ); + if( m_xContext.is() ) + return Any( m_xContext ); + else + return Any(); + } + else + { + return Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->getPropertyValue( PropertyName ); + } +} + +void OServiceManagerWrapper::disposing() +{ + m_xContext.clear(); + +// no m_root->dispose(), because every context disposes its service manager... + m_root.clear(); +} + +OServiceManagerWrapper::OServiceManagerWrapper( + Reference< XComponentContext > const & xContext ) + : t_OServiceManagerWrapper_impl( m_aMutex ) + , m_xContext( xContext ) + , m_root( xContext->getServiceManager() ) +{ + if (! m_root.is()) + { + throw RuntimeException( + "no service manager to wrap" ); + } +} + + +/** + * Create a ServiceManager + */ +OServiceManager::OServiceManager( Reference< XComponentContext > const & xContext ) + : t_OServiceManager_impl( m_aMutex ) + , m_xContext( xContext ) + , m_bInDisposing( false ) +{} + +// XComponent +void OServiceManager::dispose() +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + return; + t_OServiceManager_impl::dispose(); +} + +void OServiceManager::disposing() +{ + // dispose all factories + HashSet_Ref aImpls; + { + MutexGuard aGuard( m_aMutex ); + m_bInDisposing = true; + aImpls = m_ImplementationMap; + } + for( const auto& rxImpl : aImpls ) + { + try + { + Reference<XComponent > xComp( Reference<XComponent >::query( rxImpl ) ); + if( xComp.is() ) + xComp->dispose(); + } + catch (const RuntimeException & exc) + { + SAL_INFO("stoc", "RuntimeException occurred upon disposing factory: " << exc); + } + } + + // dispose + HashSet_Ref aImplMap; + { + MutexGuard aGuard( m_aMutex ); + // erase all members + m_ServiceMap = HashMultimap_OWString_Interface(); + aImplMap = m_ImplementationMap; + m_ImplementationMap = HashSet_Ref(); + m_ImplementationNameMap = HashMap_OWString_Interface(); + m_SetLoadedFactories= HashSet_Ref(); + } + + m_xContext.clear(); + + // not only the Event should hold the object + OSL_ASSERT( m_refCount != 1 ); +} + +// XPropertySet +Reference<XPropertySetInfo > OServiceManager::getPropertySetInfo() +{ + check_undisposed(); + if (! m_xPropertyInfo.is()) + { + Sequence< beans::Property > seq{ beans::Property( + "DefaultContext", -1, cppu::UnoType<decltype(m_xContext)>::get(), 0 ) }; + Reference< beans::XPropertySetInfo > xInfo( new PropertySetInfo_Impl( seq ) ); + + MutexGuard aGuard( m_aMutex ); + if (! m_xPropertyInfo.is()) + { + m_xPropertyInfo = xInfo; + } + } + return m_xPropertyInfo; +} + +void OServiceManager::setPropertyValue( + const OUString& PropertyName, const Any& aValue ) +{ + check_undisposed(); + if ( PropertyName != "DefaultContext" ) + { + throw UnknownPropertyException( + "unknown property " + PropertyName, + getXWeak() ); + } + + Reference< XComponentContext > xContext; + if (!(aValue >>= xContext)) + { + throw IllegalArgumentException( + "no XComponentContext given!", + getXWeak(), 1 ); + } + + MutexGuard aGuard( m_aMutex ); + m_xContext = xContext; +} + +Any OServiceManager::getPropertyValue(const OUString& PropertyName) +{ + check_undisposed(); + if ( PropertyName == "DefaultContext" ) + { + MutexGuard aGuard( m_aMutex ); + if( m_xContext.is() ) + return Any( m_xContext ); + else + return Any(); + } + else + { + UnknownPropertyException except("ServiceManager : unknown property " + PropertyName, {}); + throw except; + } +} + +void OServiceManager::addPropertyChangeListener( + const OUString&, const Reference<XPropertyChangeListener >&) +{ + check_undisposed(); + throw UnknownPropertyException("unsupported"); +} + +void OServiceManager::removePropertyChangeListener( + const OUString&, const Reference<XPropertyChangeListener >&) +{ + check_undisposed(); + throw UnknownPropertyException("unsupported"); +} + +void OServiceManager::addVetoableChangeListener( + const OUString&, const Reference<XVetoableChangeListener >&) +{ + check_undisposed(); + throw UnknownPropertyException("unsupported"); +} + +void OServiceManager::removeVetoableChangeListener( + const OUString&, const Reference<XVetoableChangeListener >&) +{ + check_undisposed(); + throw UnknownPropertyException("unsupported"); +} + +// OServiceManager +Reference<XEventListener > OServiceManager::getFactoryListener() +{ + check_undisposed(); + MutexGuard aGuard( m_aMutex ); + if( !xFactoryListener.is() ) + xFactoryListener = new OServiceManager_Listener( this ); + return xFactoryListener; +} + +// XMultiServiceFactory, XContentEnumeration +Sequence< OUString > OServiceManager::getUniqueAvailableServiceNames( + HashSet_OWString & aNameSet ) +{ + check_undisposed(); + MutexGuard aGuard( m_aMutex ); + for( const auto& rEntry : m_ServiceMap ) + aNameSet.insert( rEntry.first ); + + /* do not return the implementation names + HashMap_OWString_Interface m_ImplementationNameMap; + HashMap_OWString_Interface::iterator aIt = m_ImplementationNameMap.begin(); + while( aIt != m_ImplementationNameMap.end() ) + aNameSet.insert( (*aIt++).first ); + */ + + return comphelper::containerToSequence(aNameSet); +} + +// XMultiComponentFactory +Reference< XInterface > OServiceManager::createInstanceWithContext( + OUString const & rServiceSpecifier, + Reference< XComponentContext > const & xContext ) +{ + check_undisposed(); +#if OSL_DEBUG_LEVEL > 0 + Reference< beans::XPropertySet > xProps( xContext->getServiceManager(), UNO_QUERY ); + OSL_ASSERT( xProps.is() ); + if (xProps.is()) + { + Reference< XComponentContext > xDefContext; + xProps->getPropertyValue( "DefaultContext" ) >>= xDefContext; + OSL_ENSURE( + xContext == xDefContext, + "### default context of service manager singleton differs from context holding it!" ); + } +#endif + + const Sequence< Reference< XInterface > > factories( + queryServiceFactories( rServiceSpecifier, xContext ) ); + for ( Reference< XInterface > const & xFactory : factories ) + { + try + { + if (xFactory.is()) + { + Reference< XSingleComponentFactory > xFac( xFactory, UNO_QUERY ); + if (xFac.is()) + { + return xFac->createInstanceWithContext( xContext ); + } + else + { + Reference< XSingleServiceFactory > xFac2( xFactory, UNO_QUERY ); + if (xFac2.is()) + { + SAL_INFO("stoc", "ignoring given context raising service " << rServiceSpecifier << "!!!"); + return xFac2->createInstance(); + } + } + } + } + catch (const lang::DisposedException & exc) + { + SAL_INFO("stoc", "DisposedException occurred: " << exc); + } + } + + return Reference< XInterface >(); +} +// XMultiComponentFactory +Reference< XInterface > OServiceManager::createInstanceWithArgumentsAndContext( + OUString const & rServiceSpecifier, + Sequence< Any > const & rArguments, + Reference< XComponentContext > const & xContext ) +{ + check_undisposed(); +#if OSL_DEBUG_LEVEL > 0 + Reference< beans::XPropertySet > xProps( xContext->getServiceManager(), UNO_QUERY ); + OSL_ASSERT( xProps.is() ); + if (xProps.is()) + { + Reference< XComponentContext > xDefContext; + xProps->getPropertyValue( "DefaultContext" ) >>= xDefContext; + OSL_ENSURE( + xContext == xDefContext, + "### default context of service manager singleton differs from context holding it!" ); + } +#endif + + const Sequence< Reference< XInterface > > factories( + queryServiceFactories( rServiceSpecifier, xContext ) ); + for ( Reference< XInterface > const & xFactory : factories ) + { + try + { + if (xFactory.is()) + { + Reference< XSingleComponentFactory > xFac( xFactory, UNO_QUERY ); + if (xFac.is()) + { + return xFac->createInstanceWithArgumentsAndContext( rArguments, xContext ); + } + else + { + Reference< XSingleServiceFactory > xFac2( xFactory, UNO_QUERY ); + if (xFac2.is()) + { + SAL_INFO("stoc", "ignoring given context raising service " << rServiceSpecifier << "!!!"); + return xFac2->createInstanceWithArguments( rArguments ); + } + } + } + } + catch (const lang::DisposedException & exc) + { + SAL_INFO("stoc", "DisposedException occurred: " << exc); + } + } + + return Reference< XInterface >(); +} + +// XMultiServiceFactory, XMultiComponentFactory, XContentEnumeration +Sequence< OUString > OServiceManager::getAvailableServiceNames() +{ + check_undisposed(); + // all names + HashSet_OWString aNameSet; + return getUniqueAvailableServiceNames( aNameSet ); +} + +// XMultipleServiceFactory +Reference<XInterface > OServiceManager::createInstance( + const OUString& rServiceSpecifier ) +{ + return createInstanceWithContext( + rServiceSpecifier, m_xContext ); +} + +// XMultipleServiceFactory +Reference<XInterface > OServiceManager::createInstanceWithArguments( + const OUString& rServiceSpecifier, + const Sequence<Any >& rArguments ) +{ + return createInstanceWithArgumentsAndContext( + rServiceSpecifier, rArguments, m_xContext ); +} + +// XInitialization +void OServiceManager::initialize( Sequence< Any > const & ) +{ + check_undisposed(); + OSL_FAIL( "not impl!" ); +} + +// XServiceInfo +OUString OServiceManager::getImplementationName() +{ + return "com.sun.star.comp.stoc.OServiceManager"; +} + +// XServiceInfo +sal_Bool OServiceManager::supportsService(const OUString& ServiceName) +{ + return cppu::supportsService(this, ServiceName); +} + +// XServiceInfo +Sequence< OUString > OServiceManager::getSupportedServiceNames() +{ + return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.ServiceManager" }; +} + + +Sequence< Reference< XInterface > > OServiceManager::queryServiceFactories( + const OUString& aServiceName, Reference< XComponentContext > const & ) +{ + Sequence< Reference< XInterface > > ret; + + MutexGuard aGuard( m_aMutex ); + ::std::pair< + HashMultimap_OWString_Interface::iterator, + HashMultimap_OWString_Interface::iterator> p( + m_ServiceMap.equal_range( aServiceName ) ); + + if (p.first == p.second) // no factories + { + // no service found, look for an implementation + HashMap_OWString_Interface::iterator aIt = m_ImplementationNameMap.find( aServiceName ); + if( aIt != m_ImplementationNameMap.end() ) + { + Reference< XInterface > const & x = aIt->second; + // an implementation found + ret = Sequence< Reference< XInterface > >( &x, 1 ); + } + } + else + { + ::std::vector< Reference< XInterface > > vec; + vec.reserve( 4 ); + while (p.first != p.second) + { + vec.push_back( p.first->second ); + ++p.first; + } + ret = Sequence< Reference< XInterface > >( vec.data(), vec.size() ); + } + + return ret; +} + +// XContentEnumerationAccess +Reference<XEnumeration > OServiceManager::createContentEnumeration( + const OUString& aServiceName ) +{ + check_undisposed(); + Sequence< Reference< XInterface > > factories( + OServiceManager::queryServiceFactories( aServiceName, m_xContext ) ); + if (factories.hasElements()) + return new ServiceEnumeration_Impl( factories ); + else + return Reference< XEnumeration >(); +} + +// XEnumeration +Reference<XEnumeration > OServiceManager::createEnumeration() +{ + check_undisposed(); + MutexGuard aGuard( m_aMutex ); + return new ImplementationEnumeration_Impl( m_ImplementationMap ); +} + +// XElementAccess +Type OServiceManager::getElementType() +{ + check_undisposed(); + return cppu::UnoType<XInterface>::get(); +} + +// XElementAccess +sal_Bool OServiceManager::hasElements() +{ + check_undisposed(); + MutexGuard aGuard( m_aMutex ); + return !m_ImplementationMap.empty(); +} + +// XSet +sal_Bool OServiceManager::has( const Any & Element ) +{ + check_undisposed(); + if( Element.getValueTypeClass() == TypeClass_INTERFACE ) + { + Reference<XInterface > xEle( Element, UNO_QUERY_THROW ); + MutexGuard aGuard( m_aMutex ); + return m_ImplementationMap.find( xEle ) != + m_ImplementationMap.end(); + } + else if (auto implName = o3tl::tryAccess<OUString>(Element)) + { + MutexGuard aGuard( m_aMutex ); + return m_ImplementationNameMap.find( *implName ) != + m_ImplementationNameMap.end(); + } + return false; +} + +// XSet +void OServiceManager::insert( const Any & Element ) +{ + check_undisposed(); + if( Element.getValueTypeClass() != TypeClass_INTERFACE ) + { + throw IllegalArgumentException( + "exception interface, got " + Element.getValueType().getTypeName(), + Reference< XInterface >(), 0 ); + } + Reference<XInterface > xEle( Element, UNO_QUERY_THROW ); + + { + MutexGuard aGuard( m_aMutex ); + HashSet_Ref::iterator aIt = m_ImplementationMap.find( xEle ); + if( aIt != m_ImplementationMap.end() ) + { + throw ElementExistException( "element already exists!" ); + } + + // put into the implementation hashmap + m_ImplementationMap.insert( xEle ); + + // put into the implementation name hashmap + Reference<XServiceInfo > xInfo( Reference<XServiceInfo >::query( xEle ) ); + if( xInfo.is() ) + { + OUString aImplName = xInfo->getImplementationName(); + if( !aImplName.isEmpty() ) + m_ImplementationNameMap[ aImplName ] = xEle; + + //put into the service map + const Sequence< OUString > aServiceNames = xInfo->getSupportedServiceNames(); + for( const OUString& rServiceName : aServiceNames ) + { + m_ServiceMap.emplace( + rServiceName, *o3tl::doAccess<Reference<XInterface>>(Element) ); + } + } + } + // add the disposing listener to the factory + Reference<XComponent > xComp( Reference<XComponent >::query( xEle ) ); + if( xComp.is() ) + xComp->addEventListener( getFactoryListener() ); +} + +// helper function +bool OServiceManager::haveFactoryWithThisImplementation(const OUString& aImplName) +{ + return ( m_ImplementationNameMap.find(aImplName) != m_ImplementationNameMap.end()); +} + +// XSet +void OServiceManager::remove( const Any & Element ) +{ + if (is_disposed()) + return; + + Reference<XInterface > xEle; + if (Element.getValueTypeClass() == TypeClass_INTERFACE) + { + xEle.set( Element, UNO_QUERY_THROW ); + } + else if (auto implName = o3tl::tryAccess<OUString>(Element)) + { + MutexGuard aGuard( m_aMutex ); + HashMap_OWString_Interface::const_iterator const iFind( + m_ImplementationNameMap.find( *implName ) ); + if (iFind == m_ImplementationNameMap.end()) + { + throw NoSuchElementException( + "element is not in: " + *implName, + getXWeak() ); + } + xEle = iFind->second; + } + else + { + throw IllegalArgumentException( + "expected interface or string, got " + Element.getValueType().getTypeName(), + Reference< XInterface >(), 0 ); + } + + // remove the disposing listener from the factory + Reference<XComponent > xComp( Reference<XComponent >::query( xEle ) ); + if( xComp.is() ) + xComp->removeEventListener( getFactoryListener() ); + + MutexGuard aGuard( m_aMutex ); + HashSet_Ref::iterator aIt = m_ImplementationMap.find( xEle ); + if( aIt == m_ImplementationMap.end() ) + { + throw NoSuchElementException( + "element not found", + getXWeak() ); + } + //First remove all factories which have been loaded by ORegistryServiceManager. + m_SetLoadedFactories.erase( *aIt); + //Remove from the implementation map. It contains all factories of m_SetLoadedFactories + //which have been added directly through XSet, that is not via ORegistryServiceManager + m_ImplementationMap.erase( aIt ); + + // remove from the implementation name hashmap + Reference<XServiceInfo > xInfo( Reference<XServiceInfo >::query( xEle ) ); + if( xInfo.is() ) + { + OUString aImplName = xInfo->getImplementationName(); + if( !aImplName.isEmpty() ) + m_ImplementationNameMap.erase( aImplName ); + } + + //remove from the service map + Reference<XServiceInfo > xSF( Reference<XServiceInfo >::query( xEle ) ); + if( !xSF.is() ) + return; + + const Sequence< OUString > aServiceNames = xSF->getSupportedServiceNames(); + for( const OUString& rServiceName : aServiceNames ) + { + std::pair<HashMultimap_OWString_Interface::iterator, HashMultimap_OWString_Interface::iterator> p = + m_ServiceMap.equal_range( rServiceName ); + + while( p.first != p.second ) + { + if( xEle == (*p.first).second ) + { + m_ServiceMap.erase( p.first ); + break; + } + ++p.first; + } + } +} + +/***************************************************************************** + class ORegistryServiceManager +*****************************************************************************/ +class ORegistryServiceManager : public OServiceManager +{ +public: + explicit ORegistryServiceManager( Reference< XComponentContext > const & xContext ); + + // XInitialization + void SAL_CALL initialize(const Sequence< Any >& Arguments) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override + { return "com.sun.star.comp.stoc.ORegistryServiceManager"; } + + Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XMultiServiceFactory + Sequence< OUString > SAL_CALL getAvailableServiceNames() override; + + // XContentEnumerationAccess + //Sequence< OUString > getAvailableServiceNames() throw( (Exception) ); + Reference<XEnumeration > SAL_CALL createContentEnumeration(const OUString& aServiceName) override; + + // XComponent + void SAL_CALL dispose() override; + + // OServiceManager + Reference<XPropertySetInfo > SAL_CALL getPropertySetInfo() override; + Any SAL_CALL getPropertyValue(const OUString& PropertyName) override; + +protected: + //OServiceManager + Sequence< Reference< XInterface > > queryServiceFactories( + const OUString& aServiceName, Reference< XComponentContext > const & xContext ) override; +private: + Reference<XRegistryKey > getRootKey(); + Reference<XInterface > loadWithImplementationName( + const OUString & rImplName, Reference< XComponentContext > const & xContext ); + Sequence<OUString> getFromServiceName(std::u16string_view serviceName) const; + Reference<XInterface > loadWithServiceName( + std::u16string_view rImplName, Reference< XComponentContext > const & xContext ); + void fillAllNamesFromRegistry( HashSet_OWString & ); + + bool m_searchedRegistry; + Reference<XSimpleRegistry > m_xRegistry; // readonly property Registry + Reference<XRegistryKey > m_xRootKey; + +#if OSL_DEBUG_LEVEL > 0 + bool m_init; +#endif +}; + +/** + * Create a ServiceManager + */ +ORegistryServiceManager::ORegistryServiceManager( Reference< XComponentContext > const & xContext ) + : OServiceManager( xContext ) + , m_searchedRegistry(false) +#if OSL_DEBUG_LEVEL > 0 + , m_init( false ) +#endif +{ +} + +// XComponent +void ORegistryServiceManager::dispose() +{ + if (rBHelper.bDisposed || rBHelper.bInDispose) + return; + OServiceManager::dispose(); + // dispose + MutexGuard aGuard( m_aMutex ); + // erase all members + m_xRegistry.clear(); + m_xRootKey.clear(); +} + +/** + * Return the root key of the registry. The Default registry service is ordered + * if no registry is set. + */ +//Reference<XServiceProvider > create_DefaultRegistry_ServiceProvider(); + +Reference<XRegistryKey > ORegistryServiceManager::getRootKey() +{ + if( !m_xRootKey.is() ) + { + MutexGuard aGuard( m_aMutex ); + // DefaultRegistry suchen !!!! + if( !m_xRegistry.is() && !m_searchedRegistry ) + { + // NB. we only search this once + m_searchedRegistry = true; + + m_xRegistry.set( + createInstanceWithContext( + "com.sun.star.registry.DefaultRegistry", + m_xContext ), + UNO_QUERY ); + } + if( m_xRegistry.is() && !m_xRootKey.is() ) + m_xRootKey = m_xRegistry->getRootKey(); + } + + return m_xRootKey; +} + +/** + * Create a service provider from the registry with an implementation name + */ +Reference<XInterface > ORegistryServiceManager::loadWithImplementationName( + const OUString& name, Reference< XComponentContext > const & xContext ) +{ + Reference<XInterface > ret; + + Reference<XRegistryKey > xRootKey = getRootKey(); + if( !xRootKey.is() ) + return ret; + + try + { + OUString implementationName = "/IMPLEMENTATIONS/" + name; + Reference<XRegistryKey > xImpKey = m_xRootKey->openKey(implementationName); + + if( xImpKey.is() ) + { + Reference< lang::XMultiServiceFactory > xMgr; + if (xContext.is()) + xMgr.set( xContext->getServiceManager(), UNO_QUERY_THROW ); + else + xMgr.set( this ); + ret = createSingleRegistryFactory( xMgr, name, xImpKey ); + insert( Any( ret ) ); + // Remember this factory as loaded in contrast to inserted ( XSet::insert) + // factories. Those loaded factories in this set are candidates for being + // released on an unloading notification. + m_SetLoadedFactories.insert( ret); + } + } + catch (InvalidRegistryException &) + { + } + + return ret; +} + +/** + * Return all implementation out of the registry. + */ +Sequence<OUString> ORegistryServiceManager::getFromServiceName( + std::u16string_view serviceName ) const +{ + OUString buf = OUString::Concat("/SERVICES/") + serviceName; + return retrieveAsciiValueList( m_xRegistry, buf ); +} + +/** + * Create a service provider from the registry + */ +Reference<XInterface > ORegistryServiceManager::loadWithServiceName( + std::u16string_view serviceName, Reference< XComponentContext > const & xContext ) +{ + const Sequence<OUString> implEntries = getFromServiceName( serviceName ); + for (const auto& rEntry : implEntries) + { + Reference< XInterface > x( loadWithImplementationName( rEntry, xContext ) ); + if (x.is()) + return x; + } + + return Reference<XInterface >(); +} + +/** + * Return a sequence of all service names from the registry. + */ +void ORegistryServiceManager::fillAllNamesFromRegistry( HashSet_OWString & rSet ) +{ + Reference<XRegistryKey > xRootKey = getRootKey(); + if( !xRootKey.is() ) + return; + + try + { + Reference<XRegistryKey > xServicesKey = xRootKey->openKey( "SERVICES" ); + // root + /Services + / + if( xServicesKey.is() ) + { + sal_Int32 nPrefix = xServicesKey->getKeyName().getLength() +1; + const Sequence<Reference<XRegistryKey > > aKeys = xServicesKey->openKeys(); + std::transform(aKeys.begin(), aKeys.end(), std::inserter(rSet, rSet.end()), + [nPrefix](const Reference<XRegistryKey>& rKey) -> OUString { + return rKey->getKeyName().copy( nPrefix ); }); + } + } + catch (InvalidRegistryException &) + { + } +} + +// XInitialization +void ORegistryServiceManager::initialize(const Sequence< Any >& Arguments) +{ + check_undisposed(); + MutexGuard aGuard( m_aMutex ); + if (Arguments.hasElements()) + { + m_xRootKey.clear(); + Arguments[ 0 ] >>= m_xRegistry; + } +#if OSL_DEBUG_LEVEL > 0 + // to find all bootstrapping processes to be fixed... + OSL_ENSURE( !m_init, "### second init of service manager instance!" ); + m_init = true; +#endif +} + +// XMultiServiceFactory, XContentEnumeration +Sequence< OUString > ORegistryServiceManager::getAvailableServiceNames() +{ + check_undisposed(); + MutexGuard aGuard( m_aMutex ); + // all names + HashSet_OWString aNameSet; + + // all names from the registry + fillAllNamesFromRegistry( aNameSet ); + + return OServiceManager::getUniqueAvailableServiceNames( aNameSet ); +} + +// XServiceInfo +Sequence< OUString > ORegistryServiceManager::getSupportedServiceNames() +{ + return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.RegistryServiceManager" }; +} + + +// OServiceManager +Sequence< Reference< XInterface > > ORegistryServiceManager::queryServiceFactories( + const OUString& aServiceName, Reference< XComponentContext > const & xContext ) +{ + Sequence< Reference< XInterface > > ret( + OServiceManager::queryServiceFactories( aServiceName, xContext ) ); + if (ret.hasElements()) + { + return ret; + } + else + { + MutexGuard aGuard( m_aMutex ); + Reference< XInterface > x( loadWithServiceName( aServiceName, xContext ) ); + if (! x.is()) + x = loadWithImplementationName( aServiceName, xContext ); + return Sequence< Reference< XInterface > >( &x, 1 ); + } +} + +// XContentEnumerationAccess +Reference<XEnumeration > ORegistryServiceManager::createContentEnumeration( + const OUString& aServiceName ) +{ + check_undisposed(); + MutexGuard aGuard(m_aMutex); + // get all implementation names registered under this service name from the registry + const Sequence<OUString> aImpls = getFromServiceName( aServiceName ); + // load and insert all factories specified by the registry + for( const OUString& aImplName : aImpls ) + { + if ( !haveFactoryWithThisImplementation(aImplName) ) + { + loadWithImplementationName( aImplName, m_xContext ); + } + } + // call the superclass to enumerate all contents + return OServiceManager::createContentEnumeration( aServiceName ); +} + +// OServiceManager +Reference<XPropertySetInfo > ORegistryServiceManager::getPropertySetInfo() +{ + check_undisposed(); + if (! m_xPropertyInfo.is()) + { + Sequence< beans::Property > seq{ + beans::Property("DefaultContext", -1, cppu::UnoType<decltype(m_xContext)>::get(), 0), + beans::Property("Registry", -1, cppu::UnoType<decltype(m_xRegistry)>::get(), + beans::PropertyAttribute::READONLY) + }; + Reference< beans::XPropertySetInfo > xInfo( new PropertySetInfo_Impl( seq ) ); + + MutexGuard aGuard( m_aMutex ); + if (! m_xPropertyInfo.is()) + { + m_xPropertyInfo = xInfo; + } + } + return m_xPropertyInfo; +} + +Any ORegistryServiceManager::getPropertyValue(const OUString& PropertyName) +{ + check_undisposed(); + if ( PropertyName == "Registry" ) + { + MutexGuard aGuard( m_aMutex ); + if( m_xRegistry.is() ) + return Any( m_xRegistry ); + else + return Any(); + } + return OServiceManager::getPropertyValue( PropertyName ); +} + +} // namespace + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_stoc_OServiceManager_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new OServiceManager(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_stoc_ORegistryServiceManager_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new ORegistryServiceManager(context)); +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_stoc_OServiceManagerWrapper_get_implementation( + css::uno::XComponentContext *context, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new OServiceManagerWrapper(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |