/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 xKey = rRootKey->openKey(keyName); if( xKey.is() ) { seq = xKey->getAsciiListValue(); } } } catch( InvalidRegistryException & ) { } catch (InvalidValueException &) { } } return seq; } /***************************************************************************** Enumeration by ServiceName *****************************************************************************/ typedef std::unordered_set< Reference > HashSet_Ref; class ServiceEnumeration_Impl : public WeakImplHelper< XEnumeration > { public: explicit ServiceEnumeration_Impl( const Sequence< Reference > & rFactories ) : aFactories( rFactories ) , nIt( 0 ) {} // XEnumeration sal_Bool SAL_CALL hasMoreElements() override; Any SAL_CALL nextElement() override; private: std::mutex aMutex; Sequence< Reference > 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(u"no more elements"_ustr); return Any( &aFactories[nIt++], cppu::UnoType::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 ) { for ( sal_Int32 nPos = m_properties.getLength(); nPos--; ) { if (m_properties[nPos].Name == name) return m_properties[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(u"no more elements"_ustr); Any ret( &(*aIt), cppu::UnoType::get()); ++aIt; return ret; } /***************************************************************************** Hash tables *****************************************************************************/ typedef std::unordered_set < OUString > HashSet_OWString; typedef std::unordered_multimap < OUString, Reference > HashMultimap_OWString_Interface; typedef std::unordered_map < OUString, Reference > HashMap_OWString_Interface; /***************************************************************************** class OServiceManager_Listener *****************************************************************************/ class OServiceManager_Listener : public WeakImplHelper< XEventListener > { private: WeakReference xSMgr; public: explicit OServiceManager_Listener( const Reference & rSMgr ) : xSMgr( rSMgr ) {} // XEventListener virtual void SAL_CALL disposing(const EventObject & rEvt ) override; }; void OServiceManager_Listener::disposing(const EventObject & rEvt ) { Reference x( xSMgr ); if( !x.is() ) return; try { x->remove( Any( &rEvt.Source, cppu::UnoType::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 SAL_CALL createInstance(const OUString &) override; virtual Reference SAL_CALL createInstanceWithArguments(const OUString &, const Sequence& 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 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 SAL_CALL createContentEnumeration(const OUString& aServiceName) override; // XComponent virtual void SAL_CALL dispose() override; // XPropertySet Reference 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& aListener) override; void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference& aListener) override; void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference& aListener) override; void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference& 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 getFactoryListener(); HashMultimap_OWString_Interface m_ServiceMap; HashSet_Ref m_ImplementationMap; HashMap_OWString_Interface m_ImplementationNameMap; rtl::Reference 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( u"service manager instance has already been disposed!"_ustr, const_cast(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( u"service manager instance has already been disposed!"_ustr ); } 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 SAL_CALL createInstance(const OUString & name) override { return getRoot()->createInstanceWithContext( name, m_xContext ); } virtual Reference SAL_CALL createInstanceWithArguments(const OUString & name, const Sequence& 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 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 SAL_CALL createContentEnumeration(const OUString& aServiceName) override { return Reference< XContentEnumerationAccess >(getRoot(), UNO_QUERY_THROW)->createContentEnumeration( aServiceName ); } // XPropertySet Reference 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& aListener) override { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->addPropertyChangeListener( PropertyName, aListener ); } void SAL_CALL removePropertyChangeListener(const OUString& PropertyName, const Reference& aListener) override { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->removePropertyChangeListener( PropertyName, aListener ); } void SAL_CALL addVetoableChangeListener(const OUString& PropertyName, const Reference& aListener) override { Reference< XPropertySet >(getRoot(), UNO_QUERY_THROW)->addVetoableChangeListener( PropertyName, aListener ); } void SAL_CALL removeVetoableChangeListener(const OUString& PropertyName, const Reference& 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( u"no XComponentContext given!"_ustr, getXWeak(), 1 ); } MutexGuard aGuard( m_aMutex ); m_xContext = std::move(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( u"no service manager to wrap"_ustr ); } } /** * 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 xComp( Reference::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 OServiceManager::getPropertySetInfo() { check_undisposed(); if (! m_xPropertyInfo.is()) { Sequence< beans::Property > seq{ beans::Property( u"DefaultContext"_ustr, -1, cppu::UnoType::get(), 0 ) }; Reference< beans::XPropertySetInfo > xInfo( new PropertySetInfo_Impl( seq ) ); MutexGuard aGuard( m_aMutex ); if (! m_xPropertyInfo.is()) { m_xPropertyInfo = std::move(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( u"no XComponentContext given!"_ustr, getXWeak(), 1 ); } MutexGuard aGuard( m_aMutex ); m_xContext = std::move(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&) { check_undisposed(); throw UnknownPropertyException(u"unsupported"_ustr); } void OServiceManager::removePropertyChangeListener( const OUString&, const Reference&) { check_undisposed(); throw UnknownPropertyException(u"unsupported"_ustr); } void OServiceManager::addVetoableChangeListener( const OUString&, const Reference&) { check_undisposed(); throw UnknownPropertyException(u"unsupported"_ustr); } void OServiceManager::removeVetoableChangeListener( const OUString&, const Reference&) { check_undisposed(); throw UnknownPropertyException(u"unsupported"_ustr); } // OServiceManager Reference 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( u"DefaultContext"_ustr ) >>= 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( u"DefaultContext"_ustr ) >>= 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 OServiceManager::createInstance( const OUString& rServiceSpecifier ) { return createInstanceWithContext( rServiceSpecifier, m_xContext ); } // XMultipleServiceFactory Reference OServiceManager::createInstanceWithArguments( const OUString& rServiceSpecifier, const Sequence& 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 u"com.sun.star.comp.stoc.OServiceManager"_ustr; } // XServiceInfo sal_Bool OServiceManager::supportsService(const OUString& ServiceName) { return cppu::supportsService(this, ServiceName); } // XServiceInfo Sequence< OUString > OServiceManager::getSupportedServiceNames() { return { u"com.sun.star.lang.MultiServiceFactory"_ustr, u"com.sun.star.lang.ServiceManager"_ustr }; } 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 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 OServiceManager::createEnumeration() { check_undisposed(); MutexGuard aGuard( m_aMutex ); return new ImplementationEnumeration_Impl( m_ImplementationMap ); } // XElementAccess Type OServiceManager::getElementType() { check_undisposed(); return cppu::UnoType::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 xEle( Element, UNO_QUERY_THROW ); MutexGuard aGuard( m_aMutex ); return m_ImplementationMap.find( xEle ) != m_ImplementationMap.end(); } else if (auto implName = o3tl::tryAccess(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.getValueTypeName(), Reference< XInterface >(), 0 ); } Reference xEle( Element, UNO_QUERY_THROW ); { MutexGuard aGuard( m_aMutex ); HashSet_Ref::iterator aIt = m_ImplementationMap.find( xEle ); if( aIt != m_ImplementationMap.end() ) { throw ElementExistException( u"element already exists!"_ustr ); } // put into the implementation hashmap m_ImplementationMap.insert( xEle ); // put into the implementation name hashmap Reference xInfo( Reference::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>(Element) ); } } } // add the disposing listener to the factory Reference xComp( Reference::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 xEle; if (Element.getValueTypeClass() == TypeClass_INTERFACE) { xEle.set( Element, UNO_QUERY_THROW ); } else if (auto implName = o3tl::tryAccess(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.getValueTypeName(), Reference< XInterface >(), 0 ); } // remove the disposing listener from the factory Reference xComp( Reference::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( u"element not found"_ustr, 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 xInfo( Reference::query( xEle ) ); if( xInfo.is() ) { OUString aImplName = xInfo->getImplementationName(); if( !aImplName.isEmpty() ) m_ImplementationNameMap.erase( aImplName ); } //remove from the service map Reference xSF( Reference::query( xEle ) ); if( !xSF.is() ) return; const Sequence< OUString > aServiceNames = xSF->getSupportedServiceNames(); for( const OUString& rServiceName : aServiceNames ) { std::pair 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 u"com.sun.star.comp.stoc.ORegistryServiceManager"_ustr; } Sequence< OUString > SAL_CALL getSupportedServiceNames() override; // XMultiServiceFactory Sequence< OUString > SAL_CALL getAvailableServiceNames() override; // XContentEnumerationAccess //Sequence< OUString > getAvailableServiceNames() throw( (Exception) ); Reference SAL_CALL createContentEnumeration(const OUString& aServiceName) override; // XComponent void SAL_CALL dispose() override; // OServiceManager Reference 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 getRootKey(); Reference loadWithImplementationName( const OUString & rImplName, Reference< XComponentContext > const & xContext ); Sequence getFromServiceName(std::u16string_view serviceName) const; Reference loadWithServiceName( std::u16string_view rImplName, Reference< XComponentContext > const & xContext ); void fillAllNamesFromRegistry( HashSet_OWString & ); bool m_searchedRegistry; Reference m_xRegistry; // readonly property Registry Reference 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 create_DefaultRegistry_ServiceProvider(); Reference 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( u"com.sun.star.registry.DefaultRegistry"_ustr, 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 ORegistryServiceManager::loadWithImplementationName( const OUString& name, Reference< XComponentContext > const & xContext ) { Reference ret; Reference xRootKey = getRootKey(); if( !xRootKey.is() ) return ret; try { OUString implementationName = "/IMPLEMENTATIONS/" + name; Reference 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 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 ORegistryServiceManager::loadWithServiceName( std::u16string_view serviceName, Reference< XComponentContext > const & xContext ) { const Sequence implEntries = getFromServiceName( serviceName ); for (const auto& rEntry : implEntries) { Reference< XInterface > x( loadWithImplementationName( rEntry, xContext ) ); if (x.is()) return x; } return Reference(); } /** * Return a sequence of all service names from the registry. */ void ORegistryServiceManager::fillAllNamesFromRegistry( HashSet_OWString & rSet ) { Reference xRootKey = getRootKey(); if( !xRootKey.is() ) return; try { Reference xServicesKey = xRootKey->openKey( u"SERVICES"_ustr ); // root + /Services + / if( xServicesKey.is() ) { sal_Int32 nPrefix = xServicesKey->getKeyName().getLength() +1; const Sequence > aKeys = xServicesKey->openKeys(); std::transform(aKeys.begin(), aKeys.end(), std::inserter(rSet, rSet.end()), [nPrefix](const Reference& 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 { u"com.sun.star.lang.MultiServiceFactory"_ustr, u"com.sun.star.lang.RegistryServiceManager"_ustr }; } // 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 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 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 ORegistryServiceManager::getPropertySetInfo() { check_undisposed(); if (! m_xPropertyInfo.is()) { Sequence< beans::Property > seq{ beans::Property(u"DefaultContext"_ustr, -1, cppu::UnoType::get(), 0), beans::Property(u"Registry"_ustr, -1, cppu::UnoType::get(), beans::PropertyAttribute::READONLY) }; Reference< beans::XPropertySetInfo > xInfo( new PropertySetInfo_Impl( seq ) ); MutexGuard aGuard( m_aMutex ); if (! m_xPropertyInfo.is()) { m_xPropertyInfo = std::move(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 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 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 const &) { return cppu::acquire(new OServiceManagerWrapper(context)); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */