From 3250fad6374ef276e198faabbb1d655adeeb28f0 Mon Sep 17 00:00:00 2001 From: Stephan Bergmann Date: Tue, 15 Jan 2013 16:28:30 +0100 Subject: Extract servicemanager and typedescriptionprovider from defaultbootstrap Change-Id: I94fe7e68c5a49e591a625e9bf62108acac69428d --- cppuhelper/Library_cppuhelper.mk | 2 + cppuhelper/source/defaultbootstrap.cxx | 2051 +------------------------ cppuhelper/source/paths.cxx | 51 + cppuhelper/source/paths.hxx | 5 + cppuhelper/source/servicemanager.cxx | 1650 ++++++++++++++++++++ cppuhelper/source/servicemanager.hxx | 338 ++++ cppuhelper/source/typedescriptionprovider.cxx | 145 ++ cppuhelper/source/typedescriptionprovider.hxx | 31 + 8 files changed, 2230 insertions(+), 2043 deletions(-) create mode 100644 cppuhelper/source/servicemanager.cxx create mode 100644 cppuhelper/source/servicemanager.hxx create mode 100644 cppuhelper/source/typedescriptionprovider.cxx create mode 100644 cppuhelper/source/typedescriptionprovider.hxx (limited to 'cppuhelper') diff --git a/cppuhelper/Library_cppuhelper.mk b/cppuhelper/Library_cppuhelper.mk index 07b8a4184855..acfa4c7172a5 100644 --- a/cppuhelper/Library_cppuhelper.mk +++ b/cppuhelper/Library_cppuhelper.mk @@ -69,9 +69,11 @@ $(eval $(call gb_Library_add_exception_objects,cppuhelper,\ cppuhelper/source/propertysetmixin \ cppuhelper/source/propshlp \ cppuhelper/source/servicefactory \ + cppuhelper/source/servicemanager \ cppuhelper/source/shlib \ cppuhelper/source/supportsservice \ cppuhelper/source/tdmgr \ + cppuhelper/source/typedescriptionprovider \ cppuhelper/source/typeprovider \ cppuhelper/source/unourl \ cppuhelper/source/weak \ diff --git a/cppuhelper/source/defaultbootstrap.cxx b/cppuhelper/source/defaultbootstrap.cxx index 128ee64a9a1f..23411b1ffbb4 100644 --- a/cppuhelper/source/defaultbootstrap.cxx +++ b/cppuhelper/source/defaultbootstrap.cxx @@ -29,1959 +29,35 @@ #include "sal/config.h" -#include #include -#include -#include #include -#include "boost/noncopyable.hpp" -#include "boost/shared_ptr.hpp" -#include "com/sun/star/beans/NamedValue.hpp" -#include "com/sun/star/beans/PropertyAttribute.hpp" -#include "com/sun/star/beans/XPropertySet.hpp" -#include "com/sun/star/container/ElementExistException.hpp" -#include "com/sun/star/container/XContentEnumerationAccess.hpp" -#include "com/sun/star/container/XEnumeration.hpp" #include "com/sun/star/container/XHierarchicalNameAccess.hpp" -#include "com/sun/star/container/XNameContainer.hpp" #include "com/sun/star/container/XSet.hpp" -#include "com/sun/star/lang/XInitialization.hpp" -#include "com/sun/star/lang/XServiceInfo.hpp" -#include "com/sun/star/lang/XSingleComponentFactory.hpp" -#include "com/sun/star/lang/XSingleServiceFactory.hpp" -#include "com/sun/star/loader/XImplementationLoader.hpp" -#include "com/sun/star/registry/InvalidRegistryException.hpp" #include "com/sun/star/registry/XSimpleRegistry.hpp" #include "com/sun/star/uno/DeploymentException.hpp" #include "com/sun/star/uno/Reference.hxx" #include "com/sun/star/uno/XComponentContext.hpp" #include "cppuhelper/bootstrap.hxx" -#include "cppuhelper/compbase8.hxx" #include "cppuhelper/component_context.hxx" -#include "cppuhelper/implbase1.hxx" -#include "cppuhelper/implbase3.hxx" -#include "cppuhelper/shlib.hxx" -#include "cppuhelper/supportsservice.hxx" -#include "osl/file.hxx" -#include "registry/registry.hxx" #include "rtl/bootstrap.hxx" #include "rtl/ref.hxx" -#include "rtl/uri.hxx" #include "rtl/ustring.hxx" -#include "xmlreader/xmlreader.hxx" #include "macro_expander.hxx" #include "paths.hxx" #include "servicefactory_detail.hxx" +#include "servicemanager.hxx" +#include "typedescriptionprovider.hxx" namespace { -bool nextDirectoryItem(osl::Directory & directory, rtl::OUString * url) { - assert(url != 0); - for (;;) { - osl::DirectoryItem i; - switch (directory.getNextItem(i, SAL_MAX_UINT32)) { - case osl::FileBase::E_None: - break; - case osl::FileBase::E_NOENT: - return false; - default: - throw css::uno::DeploymentException( - "Cannot iterate directory", - css::uno::Reference< css::uno::XInterface >()); - } - osl::FileStatus stat( - osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName | - osl_FileStatus_Mask_FileURL); - if (i.getFileStatus(stat) != osl::FileBase::E_None) { - throw css::uno::DeploymentException( - "Cannot stat in directory", - css::uno::Reference< css::uno::XInterface >()); - } - if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks - // Ignore backup files: - rtl::OUString name(stat.getFileName()); - if (!(name.match(".") || name.endsWith("~"))) { - *url = stat.getFileURL(); - return true; - } - } - } -} - -void decodeRdbUri(rtl::OUString * uri, bool * optional, bool * directory) { - assert(uri != 0 && optional != 0 && directory != 0); - *optional = (*uri)[0] == '?'; - if (*optional) { - *uri = uri->copy(1); - } - *directory = uri->getLength() >= 3 && (*uri)[0] == '<' - && (*uri)[uri->getLength() - 2] == '>' - && (*uri)[uri->getLength() - 1] == '*'; - if (*directory) { - *uri = uri->copy(1, uri->getLength() - 3); - } -} - -struct ImplementationInfo: private boost::noncopyable { - ImplementationInfo( - rtl::OUString const & theName, rtl::OUString const & theLoader, - rtl::OUString const & theUri, rtl::OUString const & thePrefix, - css::uno::Reference< css::uno::XComponentContext > const & - theAlienContext, - rtl::OUString const & theRdbFile): - name(theName), loader(theLoader), uri(theUri), prefix(thePrefix), - alienContext(theAlienContext), rdbFile(theRdbFile) - {} - - explicit ImplementationInfo(rtl::OUString const & theName): name(theName) {} - - rtl::OUString const name; - rtl::OUString const loader; - rtl::OUString const uri; - rtl::OUString const prefix; - css::uno::Reference< css::uno::XComponentContext > const alienContext; - rtl::OUString const rdbFile; - std::vector< rtl::OUString > services; - std::vector< rtl::OUString > singletons; -}; - -struct Implementation: private boost::noncopyable { - Implementation( - rtl::OUString const & name, rtl::OUString const & loader, - rtl::OUString const & uri, rtl::OUString const & prefix, - css::uno::Reference< css::uno::XComponentContext > const & alienContext, - rtl::OUString const & rdbFile): - info( - new ImplementationInfo( - name, loader, uri, prefix, alienContext, rdbFile)), - loaded(false) - {} - - Implementation( - rtl::OUString const & name, - css::uno::Reference< css::lang::XSingleComponentFactory > const & - theFactory1, - css::uno::Reference< css::lang::XSingleServiceFactory > const & - theFactory2, - css::uno::Reference< css::lang::XComponent > const & theComponent): - info(new ImplementationInfo(name)), factory1(theFactory1), - factory2(theFactory2), component(theComponent), loaded(true) - {} - - boost::shared_ptr< ImplementationInfo > info; - css::uno::Reference< css::lang::XSingleComponentFactory > factory1; - css::uno::Reference< css::lang::XSingleServiceFactory > factory2; - css::uno::Reference< css::lang::XComponent > component; - bool loaded; -}; - -typedef std::map< rtl::OUString, boost::shared_ptr< Implementation > > -NamedImplementations; - -typedef - std::map< - css::uno::Reference< css::lang::XServiceInfo >, - boost::shared_ptr< Implementation > > - DynamicImplementations; - -typedef - std::map< - rtl::OUString, std::vector< boost::shared_ptr< Implementation > > > - ImplementationMap; - -void insertImplementationMap( - ImplementationMap * destination, ImplementationMap const & source) -{ - assert(destination != 0); - for (ImplementationMap::const_iterator i(source.begin()); i != source.end(); - ++i) - { - std::vector< boost::shared_ptr< Implementation > > & impls - = (*destination)[i->first]; - impls.insert(impls.end(), i->second.begin(), i->second.end()); - } -} - -void removeFromImplementationMap( - ImplementationMap * map, std::vector< rtl::OUString > const & elements, - boost::shared_ptr< Implementation > const & implementation) -{ - // The underlying data structures make this function somewhat inefficient, - // but the assumption is that it is rarely called: - assert(map != 0); - for (std::vector< rtl::OUString >::const_iterator i(elements.begin()); - i != elements.end(); ++i) - { - ImplementationMap::iterator j(map->find(*i)); - assert(j != map->end()); - std::vector< boost::shared_ptr< Implementation > >::iterator k( - std::find(j->second.begin(), j->second.end(), implementation)); - assert(k != j->second.end()); - j->second.erase(k); - if (j->second.empty()) { - map->erase(j); - } - } -} - -struct Data: private boost::noncopyable { - NamedImplementations namedImplementations; - DynamicImplementations dynamicImplementations; - ImplementationMap services; - ImplementationMap singletons; -}; - -// For simplicity, this code keeps throwing -// css::registry::InvalidRegistryException for invalid XML rdbs (even though -// that does not fit the exception's name): -class Parser: private boost::noncopyable { -public: - Parser( - rtl::OUString const & uri, - css::uno::Reference< css::uno::XComponentContext > const & alienContext, - Data * data); - -private: - void handleComponent(); - - void handleImplementation(); - - void handleService(); - - void handleSingleton(); - - rtl::OUString getNameAttribute(); - - xmlreader::XmlReader reader_; - css::uno::Reference< css::uno::XComponentContext > alienContext_; - Data * data_; - rtl::OUString attrLoader_; - rtl::OUString attrUri_; - rtl::OUString attrPrefix_; - rtl::OUString attrImplementation_; - boost::shared_ptr< Implementation > implementation_; -}; - -Parser::Parser( - rtl::OUString const & uri, - css::uno::Reference< css::uno::XComponentContext > const & alienContext, - Data * data): - reader_(uri), alienContext_(alienContext), data_(data) -{ - assert(data != 0); - int ucNsId = reader_.registerNamespaceIri( - xmlreader::Span( - RTL_CONSTASCII_STRINGPARAM( - "http://openoffice.org/2010/uno-components"))); - enum State { - STATE_BEGIN, STATE_END, STATE_COMPONENTS, STATE_COMPONENT_INITIAL, - STATE_COMPONENT, STATE_IMPLEMENTATION, STATE_SERVICE, STATE_SINGLETON }; - for (State state = STATE_BEGIN;;) { - xmlreader::Span name; - int nsId; - xmlreader::XmlReader::Result res = reader_.nextItem( - xmlreader::XmlReader::TEXT_NONE, &name, &nsId); - switch (state) { - case STATE_BEGIN: - if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId - && name.equals(RTL_CONSTASCII_STRINGPARAM("components"))) - { - state = STATE_COMPONENTS; - break; - } - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": unexpected item in outer level", - css::uno::Reference< css::uno::XInterface >()); - case STATE_END: - if (res == xmlreader::XmlReader::RESULT_DONE) { - return; - } - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": unexpected item in outer level", - css::uno::Reference< css::uno::XInterface >()); - case STATE_COMPONENTS: - if (res == xmlreader::XmlReader::RESULT_END) { - state = STATE_END; - break; - } - if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId - && name.equals(RTL_CONSTASCII_STRINGPARAM("component"))) - { - handleComponent(); - state = STATE_COMPONENT_INITIAL; - break; - } - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": unexpected item in ", - css::uno::Reference< css::uno::XInterface >()); - case STATE_COMPONENT: - if (res == xmlreader::XmlReader::RESULT_END) { - state = STATE_COMPONENTS; - break; - } - // fall through - case STATE_COMPONENT_INITIAL: - if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId - && name.equals(RTL_CONSTASCII_STRINGPARAM("implementation"))) - { - handleImplementation(); - state = STATE_IMPLEMENTATION; - break; - } - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": unexpected item in ", - css::uno::Reference< css::uno::XInterface >()); - case STATE_IMPLEMENTATION: - if (res == xmlreader::XmlReader::RESULT_END) { - state = STATE_COMPONENT; - break; - } - if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId - && name.equals(RTL_CONSTASCII_STRINGPARAM("service"))) - { - handleService(); - state = STATE_SERVICE; - break; - } - if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId - && name.equals(RTL_CONSTASCII_STRINGPARAM("singleton"))) - { - handleSingleton(); - state = STATE_SINGLETON; - break; - } - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": unexpected item in ", - css::uno::Reference< css::uno::XInterface >()); - case STATE_SERVICE: - if (res == xmlreader::XmlReader::RESULT_END) { - state = STATE_IMPLEMENTATION; - break; - } - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": unexpected item in ", - css::uno::Reference< css::uno::XInterface >()); - case STATE_SINGLETON: - if (res == xmlreader::XmlReader::RESULT_END) { - state = STATE_IMPLEMENTATION; - break; - } - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": unexpected item in ", - css::uno::Reference< css::uno::XInterface >()); - } - } -} - -void Parser::handleComponent() { - attrLoader_ = rtl::OUString(); - attrUri_ = rtl::OUString(); - attrPrefix_ = rtl::OUString(); - xmlreader::Span name; - int nsId; - while (reader_.nextAttribute(&nsId, &name)) { - if (nsId == xmlreader::XmlReader::NAMESPACE_NONE - && name.equals(RTL_CONSTASCII_STRINGPARAM("loader"))) - { - if (!attrLoader_.isEmpty()) { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() - + ": has multiple \"loader\" attributes"), - css::uno::Reference< css::uno::XInterface >()); - } - attrLoader_ = reader_.getAttributeValue(false).convertFromUtf8(); - if (attrLoader_.isEmpty()) { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() - + ": has empty \"loader\" attribute"), - css::uno::Reference< css::uno::XInterface >()); - } - } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE - && name.equals(RTL_CONSTASCII_STRINGPARAM("uri"))) - { - if (!attrUri_.isEmpty()) { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() - + ": has multiple \"uri\" attributes"), - css::uno::Reference< css::uno::XInterface >()); - } - attrUri_ = reader_.getAttributeValue(false).convertFromUtf8(); - if (attrUri_.isEmpty()) { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() - + ": has empty \"uri\" attribute"), - css::uno::Reference< css::uno::XInterface >()); - } - } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE - && name.equals(RTL_CONSTASCII_STRINGPARAM("prefix"))) - { - if (!attrPrefix_.isEmpty()) { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() + - ": has multiple \"prefix\" attributes"), - css::uno::Reference< css::uno::XInterface >()); - } - attrPrefix_ = reader_.getAttributeValue(false).convertFromUtf8(); - if (attrPrefix_.isEmpty()) { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() + - ": has empty \"prefix\" attribute"), - css::uno::Reference< css::uno::XInterface >()); - } - } else { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() + ": unexpected attribute \"" - + name.convertFromUtf8() + "\" in "), - css::uno::Reference< css::uno::XInterface >()); - } - } - if (attrLoader_.isEmpty()) { - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": is missing \"loader\" attribute", - css::uno::Reference< css::uno::XInterface >()); - } - if (attrUri_.isEmpty()) { - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": is missing \"uri\" attribute", - css::uno::Reference< css::uno::XInterface >()); - } -#ifndef DISABLE_DYNLOADING - try { - attrUri_ = rtl::Uri::convertRelToAbs(reader_.getUrl(), attrUri_); - } catch (const rtl::MalformedUriException & e) { - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": bad \"uri\" attribute: " + e.getMessage(), - css::uno::Reference< css::uno::XInterface >()); - } -#endif -} - -void Parser::handleImplementation() { - attrImplementation_ = getNameAttribute(); - implementation_.reset( - new Implementation( - attrImplementation_, attrLoader_, attrUri_, attrPrefix_, - alienContext_, reader_.getUrl())); - if (!data_->namedImplementations.insert( - NamedImplementations::value_type( - attrImplementation_, implementation_)). - second) - { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() + ": duplicate "), - css::uno::Reference< css::uno::XInterface >()); - } -} - -void Parser::handleService() { - rtl::OUString name(getNameAttribute()); - implementation_->info->services.push_back(name); - data_->services[name].push_back(implementation_); -} - -void Parser::handleSingleton() { - rtl::OUString name(getNameAttribute()); - implementation_->info->singletons.push_back(name); - data_->singletons[name].push_back(implementation_); -} - -rtl::OUString Parser::getNameAttribute() { - rtl::OUString attrName; - xmlreader::Span name; - int nsId; - while (reader_.nextAttribute(&nsId, &name)) { - if (nsId == xmlreader::XmlReader::NAMESPACE_NONE - && name.equals(RTL_CONSTASCII_STRINGPARAM("name"))) - { - if (!attrName.isEmpty()) { - throw css::registry::InvalidRegistryException( - (reader_.getUrl() - + ": element has multiple \"name\" attributes"), - css::uno::Reference< css::uno::XInterface >()); - } - attrName = reader_.getAttributeValue(false).convertFromUtf8(); - if (attrName.isEmpty()) { - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": element has empty \"name\" attribute", - css::uno::Reference< css::uno::XInterface >()); - } - } else { - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": expected element attribute \"name\"", - css::uno::Reference< css::uno::XInterface >()); - } - } - if (attrName.isEmpty()) { - throw css::registry::InvalidRegistryException( - reader_.getUrl() + ": element is missing \"name\" attribute", - css::uno::Reference< css::uno::XInterface >()); - } - return attrName; -} - -class ContentEnumeration: - public cppu::WeakImplHelper1< css::container::XEnumeration >, - private boost::noncopyable -{ -public: - explicit ContentEnumeration(std::vector< css::uno::Any > const & factories): - factories_(factories), iterator_(factories_.begin()) {} - -private: - virtual ~ContentEnumeration() {} - - virtual sal_Bool SAL_CALL hasMoreElements() - throw (css::uno::RuntimeException); - - virtual css::uno::Any SAL_CALL nextElement() - throw ( - css::container::NoSuchElementException, - css::lang::WrappedTargetException, css::uno::RuntimeException); - - osl::Mutex mutex_; - std::vector< css::uno::Any > factories_; - std::vector< css::uno::Any >::const_iterator iterator_; -}; - -sal_Bool ContentEnumeration::hasMoreElements() - throw (css::uno::RuntimeException) -{ - osl::MutexGuard g(mutex_); - return iterator_ != factories_.end(); -} - -css::uno::Any ContentEnumeration::nextElement() - throw ( - css::container::NoSuchElementException, - css::lang::WrappedTargetException, css::uno::RuntimeException) -{ - osl::MutexGuard g(mutex_); - if (iterator_ == factories_.end()) { - throw css::container::NoSuchElementException( - "Bootstrap service manager service enumerator has no more elements", - static_cast< cppu::OWeakObject * >(this)); - } - return *iterator_++; -} - -css::beans::Property getDefaultContextProperty() { - return css::beans::Property( - "DefaultContext", -1, - cppu::UnoType< css::uno::XComponentContext >::get(), - css::beans::PropertyAttribute::READONLY); -} - -typedef cppu::WeakComponentImplHelper8< - css::lang::XServiceInfo, css::lang::XMultiServiceFactory, - css::lang::XMultiComponentFactory, css::container::XSet, - css::container::XContentEnumerationAccess, css::beans::XPropertySet, - css::beans::XPropertySetInfo, css::lang::XEventListener > -ServiceManagerBase; - -class ServiceManager: - private osl::Mutex, public ServiceManagerBase, private boost::noncopyable -{ -public: - explicit ServiceManager(rtl::OUString const & rdbUris): - ServiceManagerBase(*static_cast< osl::Mutex * >(this)) - { readRdbs(rdbUris); } - - using ServiceManagerBase::acquire; - using ServiceManagerBase::release; - - void setContext( - css::uno::Reference< css::uno::XComponentContext > const & context) - { - assert(context.is()); - assert(!context_.is()); - context_ = context; - } - - css::uno::Reference< css::uno::XComponentContext > getContext() const { - assert(context_.is()); - return context_; - } - - Data const & getData() const { return data_; } - - void loadImplementation( - css::uno::Reference< css::uno::XComponentContext > const & context, - boost::shared_ptr< ImplementationInfo > const & info, - css::uno::Reference< css::lang::XSingleComponentFactory > * factory1, - css::uno::Reference< css::lang::XSingleServiceFactory > * factory2); - - virtual rtl::OUString SAL_CALL getImplementationName() - throw (css::uno::RuntimeException); - - virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) - throw (css::uno::RuntimeException); - - virtual css::uno::Sequence< rtl::OUString > SAL_CALL - getSupportedServiceNames() throw (css::uno::RuntimeException); - - virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( - rtl::OUString const & aServiceSpecifier) - throw (css::uno::Exception, css::uno::RuntimeException); - - virtual css::uno::Reference< css::uno::XInterface > SAL_CALL - createInstanceWithArguments( - rtl::OUString const & ServiceSpecifier, - css::uno::Sequence< css::uno::Any > const & Arguments) - throw (css::uno::Exception, css::uno::RuntimeException); - - virtual css::uno::Sequence< rtl::OUString > SAL_CALL - getAvailableServiceNames() throw (css::uno::RuntimeException); - - virtual css::uno::Reference< css::uno::XInterface > SAL_CALL - createInstanceWithContext( - rtl::OUString const & aServiceSpecifier, - css::uno::Reference< css::uno::XComponentContext > const & Context) - throw (css::uno::Exception, css::uno::RuntimeException); - - virtual css::uno::Reference< css::uno::XInterface > SAL_CALL - createInstanceWithArgumentsAndContext( - rtl::OUString const & ServiceSpecifier, - css::uno::Sequence< css::uno::Any > const & Arguments, - css::uno::Reference< css::uno::XComponentContext > const & Context) - throw (css::uno::Exception, css::uno::RuntimeException); - - virtual css::uno::Type SAL_CALL getElementType() - throw (css::uno::RuntimeException); - - virtual sal_Bool SAL_CALL hasElements() throw (css::uno::RuntimeException); - - virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL - createEnumeration() throw (css::uno::RuntimeException); - - virtual sal_Bool SAL_CALL has(css::uno::Any const & aElement) - throw (css::uno::RuntimeException); - - virtual void SAL_CALL insert(css::uno::Any const & aElement) - throw ( - css::lang::IllegalArgumentException, - css::container::ElementExistException, css::uno::RuntimeException); - - virtual void SAL_CALL remove(css::uno::Any const & aElement) - throw ( - css::lang::IllegalArgumentException, - css::container::NoSuchElementException, css::uno::RuntimeException); - - virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL - createContentEnumeration(rtl::OUString const & aServiceName) - throw (css::uno::RuntimeException); - - virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL - getPropertySetInfo() throw (css::uno::RuntimeException); - - virtual void SAL_CALL setPropertyValue( - rtl::OUString const & aPropertyName, css::uno::Any const & aValue) - throw ( - css::beans::UnknownPropertyException, - css::beans::PropertyVetoException, - css::lang::IllegalArgumentException, - css::lang::WrappedTargetException, css::uno::RuntimeException); - - virtual css::uno::Any SAL_CALL getPropertyValue( - rtl::OUString const & PropertyName) - throw ( - css::beans::UnknownPropertyException, - css::lang::WrappedTargetException, css::uno::RuntimeException); - - virtual void SAL_CALL addPropertyChangeListener( - rtl::OUString const & aPropertyName, - css::uno::Reference< css::beans::XPropertyChangeListener > const & - xListener) - throw ( - css::beans::UnknownPropertyException, - css::lang::WrappedTargetException, css::uno::RuntimeException); - - virtual void SAL_CALL removePropertyChangeListener( - rtl::OUString const & aPropertyName, - css::uno::Reference< css::beans::XPropertyChangeListener > const & - aListener) - throw ( - css::beans::UnknownPropertyException, - css::lang::WrappedTargetException, css::uno::RuntimeException); - - virtual void SAL_CALL addVetoableChangeListener( - rtl::OUString const & PropertyName, - css::uno::Reference< css::beans::XVetoableChangeListener > const & - aListener) - throw ( - css::beans::UnknownPropertyException, - css::lang::WrappedTargetException, css::uno::RuntimeException); - - virtual void SAL_CALL removeVetoableChangeListener( - rtl::OUString const & PropertyName, - css::uno::Reference< css::beans::XVetoableChangeListener > const & - aListener) - throw ( - css::beans::UnknownPropertyException, - css::lang::WrappedTargetException, css::uno::RuntimeException); - - virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() - throw (css::uno::RuntimeException); - - virtual css::beans::Property SAL_CALL getPropertyByName( - rtl::OUString const & aName) - throw ( - css::beans::UnknownPropertyException, css::uno::RuntimeException); - - virtual sal_Bool SAL_CALL hasPropertyByName(rtl::OUString const & Name) - throw (css::uno::RuntimeException); - - virtual void SAL_CALL disposing(css::lang::EventObject const & Source) - throw (css::uno::RuntimeException); - -private: - virtual ~ServiceManager() {} - - virtual void SAL_CALL disposing(); - - // needs to be called with rBHelper.rMutex locked: - bool isDisposed() { return rBHelper.bDisposed || rBHelper.bInDispose; } - - void removeEventListenerFromComponent( - css::uno::Reference< css::lang::XComponent > const & component); - - void readRdbs(rtl::OUString const & uris); - - void readRdbDirectory(rtl::OUString const & uri, bool optional); - - void readRdbFile(rtl::OUString const & uri, bool optional); - - bool readLegacyRdbFile(rtl::OUString const & uri); - - rtl::OUString readLegacyRdbString( - rtl::OUString const & uri, RegistryKey & key, - rtl::OUString const & path); - - void readLegacyRdbStrings( - rtl::OUString const & uri, RegistryKey & key, - rtl::OUString const & path, std::vector< rtl::OUString > * strings); - - void insertRdbFiles( - std::vector< rtl::OUString > const & uris, - css::uno::Reference< css::uno::XComponentContext > const & - alientContext); - - void insertLegacyFactory( - css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo); - - bool insertExtraData(Data const & extra); - - void removeRdbFiles(std::vector< rtl::OUString > const & uris); - - bool removeLegacyFactory( - css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo, - bool removeListener); - - void removeImplementation(rtl::OUString name); - - boost::shared_ptr< Implementation > findServiceImplementation( - css::uno::Reference< css::uno::XComponentContext > const & context, - rtl::OUString const & specifier); - - css::uno::Reference< css::uno::XComponentContext > context_; - Data data_; -}; - -class FactoryWrapper: - public cppu::WeakImplHelper3< - css::lang::XSingleComponentFactory, css::lang::XSingleServiceFactory, - css::lang::XServiceInfo >, - private boost::noncopyable -{ -public: - FactoryWrapper( - rtl::Reference< ServiceManager > const & manager, - boost::shared_ptr< ImplementationInfo > const & info): - manager_(manager), info_(info), loaded_(false) - { assert(manager.is() && info.get() != 0); } - -private: - virtual ~FactoryWrapper() {} - - virtual css::uno::Reference< css::uno::XInterface > SAL_CALL - createInstanceWithContext( - css::uno::Reference< css::uno::XComponentContext > const & Context) - throw (css::uno::Exception, css::uno::RuntimeException); - - virtual css::uno::Reference< css::uno::XInterface > SAL_CALL - createInstanceWithArgumentsAndContext( - css::uno::Sequence< css::uno::Any > const & Arguments, - css::uno::Reference< css::uno::XComponentContext > const & Context) - throw (css::uno::Exception, css::uno::RuntimeException); - - virtual css::uno::Reference< css::uno::XInterface > SAL_CALL - createInstance() throw (css::uno::Exception, css::uno::RuntimeException); - - virtual css::uno::Reference< css::uno::XInterface > SAL_CALL - createInstanceWithArguments( - css::uno::Sequence< css::uno::Any > const & Arguments) - throw (css::uno::Exception, css::uno::RuntimeException); - - virtual rtl::OUString SAL_CALL getImplementationName() - throw (css::uno::RuntimeException); - - virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) - throw (css::uno::RuntimeException); - - virtual css::uno::Sequence< rtl::OUString > SAL_CALL - getSupportedServiceNames() throw (css::uno::RuntimeException); - - void loadImplementation( - css::uno::Reference< css::uno::XComponentContext > const & context); - - rtl::Reference< ServiceManager > manager_; - boost::shared_ptr< ImplementationInfo > info_; - - osl::Mutex mutex_; - bool loaded_; - css::uno::Reference< css::lang::XSingleComponentFactory > factory1_; - css::uno::Reference< css::lang::XSingleServiceFactory > factory2_; -}; - -void ServiceManager::loadImplementation( - css::uno::Reference< css::uno::XComponentContext > const & context, - boost::shared_ptr< ImplementationInfo > const & info, - css::uno::Reference< css::lang::XSingleComponentFactory > * factory1, - css::uno::Reference< css::lang::XSingleServiceFactory > * factory2) -{ - assert( - info.get() != 0 && factory1 != 0 && !factory1->is() && factory2 != 0 - && !factory2->is()); - rtl::OUString uri; - try { - uri = cppu::bootstrap_expandUri(info->uri); - } catch (css::lang::IllegalArgumentException & e) { - throw css::uno::DeploymentException( - "Cannot expand URI" + info->uri + ": " + e.Message, - static_cast< cppu::OWeakObject * >(this)); - } - css::uno::Reference< css::uno::XInterface > f0; - // Shortcut loading via SharedLibrary loader, to pass in prefix argument - // (which the loader's activate implementation would normally obtain through - // the legacy xKey argument): - if (!info->alienContext.is() - && info->loader == "com.sun.star.loader.SharedLibrary") - { - rtl::OUString prefix(info->prefix); - if (!prefix.isEmpty()) { - prefix += "_"; - } - f0 = cppu::loadSharedLibComponentFactory( - uri, rtl::OUString(), info->name, this, - css::uno::Reference< css::registry::XRegistryKey >(), prefix); - } else { - SAL_INFO_IF( - !info->prefix.isEmpty(), "cppuhelper", - "Loader " << info->loader << " and non-empty prefix " - << info->prefix); - css::uno::Reference< css::uno::XComponentContext > ctxt; - css::uno::Reference< css::lang::XMultiComponentFactory > smgr; - if (info->alienContext.is()) { - ctxt = info->alienContext; - smgr = css::uno::Reference< css::lang::XMultiComponentFactory >( - ctxt->getServiceManager(), css::uno::UNO_SET_THROW); - } else { - assert(context.is()); - ctxt = context; - smgr = this; - } - css::uno::Reference< css::loader::XImplementationLoader > loader( - smgr->createInstanceWithContext(info->loader, ctxt), - css::uno::UNO_QUERY_THROW); - f0 = loader->activate( - info->name, rtl::OUString(), uri, - css::uno::Reference< css::registry::XRegistryKey >()); - } - factory1->set(f0, css::uno::UNO_QUERY); - if (!factory1->is()) { - factory2->set(f0, css::uno::UNO_QUERY); - } -} - -rtl::OUString ServiceManager::getImplementationName() - throw (css::uno::RuntimeException) -{ - return rtl::OUString( - "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager"); -} - -sal_Bool ServiceManager::supportsService(rtl::OUString const & ServiceName) - throw (css::uno::RuntimeException) -{ - return cppu::supportsService(this, ServiceName); -} - -css::uno::Sequence< rtl::OUString > ServiceManager::getSupportedServiceNames() - throw (css::uno::RuntimeException) -{ - css::uno::Sequence< rtl::OUString > names(2); - names[0] = "com.sun.star.lang.MultiServiceFactory"; - names[1] = "com.sun.star.lang.ServiceManager"; - return names; -} - -css::uno::Reference< css::uno::XInterface > ServiceManager::createInstance( - rtl::OUString const & aServiceSpecifier) - throw (css::uno::Exception, css::uno::RuntimeException) -{ - assert(context_.is()); - return createInstanceWithContext(aServiceSpecifier, context_); -} - -css::uno::Reference< css::uno::XInterface > -ServiceManager::createInstanceWithArguments( - rtl::OUString const & ServiceSpecifier, - css::uno::Sequence< css::uno::Any > const & Arguments) - throw (css::uno::Exception, css::uno::RuntimeException) -{ - assert(context_.is()); - return createInstanceWithArgumentsAndContext( - ServiceSpecifier, Arguments, context_); -} - -css::uno::Sequence< rtl::OUString > ServiceManager::getAvailableServiceNames() - throw (css::uno::RuntimeException) -{ - osl::MutexGuard g(rBHelper.rMutex); - if (isDisposed()) { - return css::uno::Sequence< rtl::OUString >(); - } - ImplementationMap::size_type n = data_.services.size(); - if (n > static_cast< sal_uInt32 >(SAL_MAX_INT32)) { - throw css::uno::RuntimeException( - "getAvailableServiceNames: too many services", - static_cast< cppu::OWeakObject * >(this)); - } - css::uno::Sequence< rtl::OUString > names(static_cast< sal_Int32 >(n)); - sal_Int32 i = 0; - for (ImplementationMap::const_iterator j(data_.services.begin()); - j != data_.services.end(); ++j) - { - names[i++] = j->first; - } - assert(i == names.getLength()); - return names; -} - -css::uno::Reference< css::uno::XInterface > -ServiceManager::createInstanceWithContext( - rtl::OUString const & aServiceSpecifier, - css::uno::Reference< css::uno::XComponentContext > const & Context) - throw (css::uno::Exception, css::uno::RuntimeException) -{ - boost::shared_ptr< Implementation > impl( - findServiceImplementation(Context, aServiceSpecifier)); - if (impl.get() == 0) { - return css::uno::Reference< css::uno::XInterface >(); - } - if (impl->factory1.is()) { - return impl->factory1->createInstanceWithContext(Context); - } - if (impl->factory2.is()) { - return impl->factory2->createInstance(); - } - throw css::uno::DeploymentException( - "Implementation " + impl->info->name + " does not provide a factory", - static_cast< cppu::OWeakObject * >(this)); -} - -css::uno::Reference< css::uno::XInterface > -ServiceManager::createInstanceWithArgumentsAndContext( - rtl::OUString const & ServiceSpecifier, - css::uno::Sequence< css::uno::Any > const & Arguments, - css::uno::Reference< css::uno::XComponentContext > const & Context) - throw (css::uno::Exception, css::uno::RuntimeException) -{ - boost::shared_ptr< Implementation > impl( - findServiceImplementation(Context, ServiceSpecifier)); - if (impl.get() == 0) { - return css::uno::Reference< css::uno::XInterface >(); - } - if (impl->factory1.is()) { - return impl->factory1->createInstanceWithArgumentsAndContext( - Arguments, Context); - } - if (impl->factory2.is()) { - return impl->factory2->createInstanceWithArguments(Arguments); - } - throw css::uno::DeploymentException( - "Implementation " + impl->info->name + " does not provide a factory", - static_cast< cppu::OWeakObject * >(this)); -} - -css::uno::Type ServiceManager::getElementType() - throw (css::uno::RuntimeException) -{ - return css::uno::Type(); -} - -sal_Bool ServiceManager::hasElements() throw (css::uno::RuntimeException) { - osl::MutexGuard g(rBHelper.rMutex); - return - !(data_.namedImplementations.empty() - && data_.dynamicImplementations.empty()); -} - -css::uno::Reference< css::container::XEnumeration > -ServiceManager::createEnumeration() throw (css::uno::RuntimeException) { - throw css::uno::RuntimeException( - "ServiceManager createEnumeration: method not supported", - static_cast< cppu::OWeakObject * >(this)); -} - -sal_Bool ServiceManager::has(css::uno::Any const &) - throw (css::uno::RuntimeException) -{ - throw css::uno::RuntimeException( - "ServiceManager has: method not supported", - static_cast< cppu::OWeakObject * >(this)); -} - -void ServiceManager::insert(css::uno::Any const & aElement) - throw ( - css::lang::IllegalArgumentException, - css::container::ElementExistException, css::uno::RuntimeException) -{ - css::uno::Sequence< css::beans::NamedValue > args; - if (aElement >>= args) { - std::vector< rtl::OUString > uris; - css::uno::Reference< css::uno::XComponentContext > alienContext; - for (sal_Int32 i = 0; i < args.getLength(); ++i) { - if (args[i].Name == "uri") { - rtl::OUString uri; - if (!(args[i].Value >>= uri)) { - throw css::lang::IllegalArgumentException( - "Bad uri argument", - static_cast< cppu::OWeakObject * >(this), 0); - } - uris.push_back(uri); - } else if (args[i].Name == "component-context") { - if (alienContext.is()) { - throw css::lang::IllegalArgumentException( - "Multiple component-context arguments", - static_cast< cppu::OWeakObject * >(this), 0); - } - if (!(args[i].Value >>= alienContext) || !alienContext.is()) { - throw css::lang::IllegalArgumentException( - "Bad component-context argument", - static_cast< cppu::OWeakObject * >(this), 0); - } - } else { - throw css::lang::IllegalArgumentException( - "Bad argument " + args[i].Name, - static_cast< cppu::OWeakObject * >(this), 0); - } - } - insertRdbFiles(uris, alienContext); - return; - } - css::uno::Reference< css::lang::XServiceInfo > info; - if ((aElement >>= info) && info.is()) { - insertLegacyFactory(info); - return; - } -// At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in -// module languagetool) contain an (actively registered) factory that does not -// implement XServiceInfo (see "SingletonFactory should -// implement XServiceInfo"); the old OServiceManager::insert -// (stoc/source/servicemanager/servicemanager.cxx) silently did not add such -// broken factories to its m_ImplementationNameMap, so ignore them here for -// backwards compatibility of live-insertion of extensions, too. - -// (The plan was that this warning would go away (and we would do the -// throw instead) for the incompatible LO 4, but we changed our mind): - css::uno::Reference< css::lang::XSingleComponentFactory > legacy; - if ((aElement >>= legacy) && legacy.is()) { - SAL_WARN( - "cppuhelper", - "Ignored XSingleComponentFactory not implementing XServiceInfo"); - return; - } - - throw css::lang::IllegalArgumentException( - "Bad insert element", static_cast< cppu::OWeakObject * >(this), 0); -} - -void ServiceManager::remove(css::uno::Any const & aElement) - throw ( - css::lang::IllegalArgumentException, - css::container::NoSuchElementException, css::uno::RuntimeException) -{ - css::uno::Sequence< css::beans::NamedValue > args; - if (aElement >>= args) { - std::vector< rtl::OUString > uris; - for (sal_Int32 i = 0; i < args.getLength(); ++i) { - if (args[i].Name == "uri") { - rtl::OUString uri; - if (!(args[i].Value >>= uri)) { - throw css::lang::IllegalArgumentException( - "Bad uri argument", - static_cast< cppu::OWeakObject * >(this), 0); - } - uris.push_back(uri); - } else { - throw css::lang::IllegalArgumentException( - "Bad argument " + args[i].Name, - static_cast< cppu::OWeakObject * >(this), 0); - } - } - removeRdbFiles(uris); - return; - } - css::uno::Reference< css::lang::XServiceInfo > info; - if ((aElement >>= info) && info.is()) { - if (!removeLegacyFactory(info, true)) { - throw css::container::NoSuchElementException( - "Remove non-inserted factory object", - static_cast< cppu::OWeakObject * >(this)); - } - return; - } - rtl::OUString impl; - if (aElement >>= impl) { - // For live-removal of extensions: - removeImplementation(impl); - return; - } - throw css::lang::IllegalArgumentException( - "Bad remove element", static_cast< cppu::OWeakObject * >(this), 0); -} - -css::uno::Reference< css::container::XEnumeration > -ServiceManager::createContentEnumeration(rtl::OUString const & aServiceName) - throw (css::uno::RuntimeException) -{ - std::vector< boost::shared_ptr< Implementation > > impls; - { - osl::MutexGuard g(rBHelper.rMutex); - ImplementationMap::const_iterator i(data_.services.find(aServiceName)); - if (i != data_.services.end()) { - impls = i->second; - } - } - std::vector< css::uno::Any > factories; - for (std::vector< boost::shared_ptr< Implementation > >::const_iterator i( - impls.begin()); - i != impls.end(); ++i) - { - Implementation * impl = i->get(); - assert(impl != 0); - { - osl::MutexGuard g(rBHelper.rMutex); - if (isDisposed()) { - factories.clear(); - break; - } - if (!impl->loaded) { - // Postpone actual factory instantiation as long as possible (so - // that e.g. opening LO's "Tools - Macros" menu does not try to - // instantiate a JVM, which can lead to a synchronous error - // dialog when no JVM is specified, and showing the dialog while - // hovering over a menu can cause trouble): - impl->factory1 = new FactoryWrapper(this, impl->info); - impl->loaded = true; - } - } - if (impl->factory1.is()) { - factories.push_back(css::uno::makeAny(impl->factory1)); - } else if (impl->factory2.is()) { - factories.push_back(css::uno::makeAny(impl->factory2)); - } else { - throw css::uno::DeploymentException( - ("Implementation " + impl->info->name - + " does not provide a factory"), - static_cast< cppu::OWeakObject * >(this)); - } - } - return new ContentEnumeration(factories); -} - -css::uno::Reference< css::beans::XPropertySetInfo > -ServiceManager::getPropertySetInfo() throw (css::uno::RuntimeException) { - return this; -} - -void ServiceManager::setPropertyValue( - rtl::OUString const & aPropertyName, css::uno::Any const &) - throw ( - css::beans::UnknownPropertyException, css::beans::PropertyVetoException, - css::lang::IllegalArgumentException, css::lang::WrappedTargetException, - css::uno::RuntimeException) -{ - if (aPropertyName == "DefaultContext") { - throw css::beans::PropertyVetoException( - aPropertyName, static_cast< cppu::OWeakObject * >(this)); - } else { - throw css::beans::UnknownPropertyException( - aPropertyName, static_cast< cppu::OWeakObject * >(this)); - } -} - -css::uno::Any ServiceManager::getPropertyValue( - rtl::OUString const & PropertyName) - throw ( - css::beans::UnknownPropertyException, css::lang::WrappedTargetException, - css::uno::RuntimeException) -{ - if (PropertyName != "DefaultContext") { - throw css::beans::UnknownPropertyException( - PropertyName, static_cast< cppu::OWeakObject * >(this)); - } - assert(context_.is()); - return css::uno::makeAny(context_); -} - -void ServiceManager::addPropertyChangeListener( - rtl::OUString const & aPropertyName, - css::uno::Reference< css::beans::XPropertyChangeListener > const & - xListener) - throw ( - css::beans::UnknownPropertyException, css::lang::WrappedTargetException, - css::uno::RuntimeException) -{ - if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") { - throw css::beans::UnknownPropertyException( - aPropertyName, static_cast< cppu::OWeakObject * >(this)); - } - // DefaultContext does not change, so just treat it as an event listener: - return addEventListener(xListener.get()); -} - -void ServiceManager::removePropertyChangeListener( - rtl::OUString const & aPropertyName, - css::uno::Reference< css::beans::XPropertyChangeListener > const & - aListener) - throw ( - css::beans::UnknownPropertyException, css::lang::WrappedTargetException, - css::uno::RuntimeException) -{ - if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") { - throw css::beans::UnknownPropertyException( - aPropertyName, static_cast< cppu::OWeakObject * >(this)); - } - // DefaultContext does not change, so just treat it as an event listener: - return removeEventListener(aListener.get()); -} - -void ServiceManager::addVetoableChangeListener( - rtl::OUString const & PropertyName, - css::uno::Reference< css::beans::XVetoableChangeListener > const & - aListener) - throw ( - css::beans::UnknownPropertyException, css::lang::WrappedTargetException, - css::uno::RuntimeException) -{ - if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") { - throw css::beans::UnknownPropertyException( - PropertyName, static_cast< cppu::OWeakObject * >(this)); - } - // DefaultContext does not change, so just treat it as an event listener: - return addEventListener(aListener.get()); -} - -void ServiceManager::removeVetoableChangeListener( - rtl::OUString const & PropertyName, - css::uno::Reference< css::beans::XVetoableChangeListener > const & - aListener) - throw ( - css::beans::UnknownPropertyException, css::lang::WrappedTargetException, - css::uno::RuntimeException) -{ - if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") { - throw css::beans::UnknownPropertyException( - PropertyName, static_cast< cppu::OWeakObject * >(this)); - } - // DefaultContext does not change, so just treat it as an event listener: - return removeEventListener(aListener.get()); -} - -css::uno::Sequence< css::beans::Property > ServiceManager::getProperties() - throw (css::uno::RuntimeException) -{ - css::uno::Sequence< css::beans::Property > props(1); - props[0] = getDefaultContextProperty(); - return props; -} - -css::beans::Property ServiceManager::getPropertyByName( - rtl::OUString const & aName) - throw (css::beans::UnknownPropertyException, css::uno::RuntimeException) -{ - if (aName != "DefaultContext") { - throw css::beans::UnknownPropertyException( - aName, static_cast< cppu::OWeakObject * >(this)); - } - return getDefaultContextProperty(); -} - -sal_Bool ServiceManager::hasPropertyByName(rtl::OUString const & Name) - throw (css::uno::RuntimeException) -{ - return Name == "DefaultContext"; -} - -void ServiceManager::disposing(css::lang::EventObject const & Source) - throw (css::uno::RuntimeException) -{ - removeLegacyFactory( - css::uno::Reference< css::lang::XServiceInfo >( - Source.Source, css::uno::UNO_QUERY_THROW), - false); -} - -void ServiceManager::disposing() { - std::vector< css::uno::Reference< css::lang::XComponent > > comps; - Data clear; - { - osl::MutexGuard g(rBHelper.rMutex); - for (DynamicImplementations::const_iterator i( - data_.dynamicImplementations.begin()); - i != data_.dynamicImplementations.end(); ++i) - { - assert(i->second.get() != 0); - if (i->second->component.is()) { - comps.push_back(i->second->component); - } - } - data_.namedImplementations.swap(clear.namedImplementations); - data_.dynamicImplementations.swap(clear.dynamicImplementations); - data_.services.swap(clear.services); - data_.singletons.swap(clear.singletons); - } - for (std::vector< - css::uno::Reference< css::lang::XComponent > >::const_iterator i( - comps.begin()); - i != comps.end(); ++i) - { - removeEventListenerFromComponent(*i); - } -} - -void ServiceManager::removeEventListenerFromComponent( - css::uno::Reference< css::lang::XComponent > const & component) -{ - assert(component.is()); - try { - component->removeEventListener(this); - } catch (css::uno::RuntimeException & e) { - SAL_INFO( - "cppuhelper", - "Ignored removeEventListener RuntimeException " + e.Message); - } -} - -void ServiceManager::readRdbs(rtl::OUString const & uris) { - for (sal_Int32 i = 0; i != -1;) { - rtl::OUString uri(uris.getToken(0, ' ', i)); - if (uri.isEmpty()) { - continue; - } - bool optional; - bool directory; - decodeRdbUri(&uri, &optional, &directory); - if (directory) { - readRdbDirectory(uri, optional); - } else { - readRdbFile(uri, optional); - } - } -} - -void ServiceManager::readRdbDirectory(rtl::OUString const & uri, bool optional) -{ - osl::Directory dir(uri); - switch (dir.open()) { - case osl::FileBase::E_None: - break; - case osl::FileBase::E_NOENT: - if (optional) { - SAL_INFO("cppuhelper", "Ignored optional " << uri); - return; - } - // fall through - default: - throw css::uno::DeploymentException( - "Cannot open directory " + uri, - static_cast< cppu::OWeakObject * >(this)); - } - for (;;) { - rtl::OUString url; - if (!nextDirectoryItem(dir, &url)) { - break; - } - readRdbFile(url, false); - } -} - -void ServiceManager::readRdbFile(rtl::OUString const & uri, bool optional) { - try { - Parser( - uri, css::uno::Reference< css::uno::XComponentContext >(), &data_); - } catch (css::container::NoSuchElementException &) { - if (!optional) { - throw css::uno::DeploymentException( - uri + ": no such file", - static_cast< cppu::OWeakObject * >(this)); - } - SAL_INFO("cppuhelper", "Ignored optional " << uri); - } catch (css::registry::InvalidRegistryException & e) { - if (!readLegacyRdbFile(uri)) { - throw css::uno::DeploymentException( - "InvalidRegistryException: " + e.Message, - static_cast< cppu::OWeakObject * >(this)); - } - } catch (css::uno::RuntimeException &) { - if (!readLegacyRdbFile(uri)) { - throw; - } - } -} - -bool ServiceManager::readLegacyRdbFile(rtl::OUString const & uri) { - Registry reg; - switch (reg.open(uri, REG_READONLY)) { - case REG_NO_ERROR: - break; - case REG_REGISTRY_NOT_EXISTS: - case REG_INVALID_REGISTRY: - { - // Ignore empty rdb files (which are at least seen by subordinate - // uno processes during extension registration; Registry::open can - // fail on them if mmap(2) returns EINVAL for a zero length): - osl::DirectoryItem item; - if (osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None) { - osl::FileStatus status(osl_FileStatus_Mask_FileSize); - if (item.getFileStatus(status) == osl::FileBase::E_None - && status.getFileSize() == 0) - { - return true; - } - } - } - // fall through - default: - return false; - } - RegistryKey rootKey; - if (reg.openRootKey(rootKey) != REG_NO_ERROR) { - throw css::uno::DeploymentException( - "Failure reading legacy rdb file " + uri, - static_cast< cppu::OWeakObject * >(this)); - } - RegistryKeyArray impls; - switch (rootKey.openSubKeys("IMPLEMENTATIONS", impls)) { - case REG_NO_ERROR: - break; - case REG_KEY_NOT_EXISTS: - return true; - default: - throw css::uno::DeploymentException( - "Failure reading legacy rdb file " + uri, - static_cast< cppu::OWeakObject * >(this)); - } - for (sal_uInt32 i = 0; i != impls.getLength(); ++i) { - RegistryKey implKey(impls.getElement(i)); - assert(implKey.getName().match("/IMPLEMENTATIONS/")); - rtl::OUString name( - implKey.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/"))); - boost::shared_ptr< Implementation > impl( - new Implementation( - name, readLegacyRdbString(uri, implKey, "UNO/ACTIVATOR"), - readLegacyRdbString(uri, implKey, "UNO/LOCATION"), - rtl::OUString(), - css::uno::Reference< css::uno::XComponentContext >(), uri)); - if (!data_.namedImplementations.insert( - NamedImplementations::value_type(name, impl)). - second) - { - throw css::registry::InvalidRegistryException( - uri + ": duplicate ", - css::uno::Reference< css::uno::XInterface >()); - } - readLegacyRdbStrings( - uri, implKey, "UNO/SERVICES", &impl->info->services); - for (std::vector< rtl::OUString >::const_iterator j( - impl->info->services.begin()); - j != impl->info->services.end(); ++j) - { - data_.services[*j].push_back(impl); - } - readLegacyRdbStrings( - uri, implKey, "UNO/SINGLETONS", &impl->info->singletons); - for (std::vector< rtl::OUString >::const_iterator j( - impl->info->singletons.begin()); - j != impl->info->singletons.end(); ++j) - { - data_.singletons[*j].push_back(impl); - } - } - return true; -} - -rtl::OUString ServiceManager::readLegacyRdbString( - rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path) -{ - RegistryKey subkey; - RegValueType t; - sal_uInt32 s(0); - if (key.openKey(path, subkey) != REG_NO_ERROR - || subkey.getValueInfo(rtl::OUString(), &t, &s) != REG_NO_ERROR - || t != RG_VALUETYPE_STRING - || s == 0 || s > static_cast< sal_uInt32 >(SAL_MAX_INT32)) - { - throw css::uno::DeploymentException( - "Failure reading legacy rdb file " + uri, - static_cast< cppu::OWeakObject * >(this)); - } - rtl::OUString val; - std::vector< char > v(s); // assuming sal_uInt32 fits into vector::size_type - if (subkey.getValue(rtl::OUString(), &v[0]) != REG_NO_ERROR - || v.back() != '\0' - || !rtl_convertStringToUString( - &val.pData, &v[0], static_cast< sal_Int32 >(s - 1), - RTL_TEXTENCODING_UTF8, - (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR - | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR - | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) - { - throw css::uno::DeploymentException( - "Failure reading legacy rdb file " + uri, - static_cast< cppu::OWeakObject * >(this)); - } - return val; -} - -void ServiceManager::readLegacyRdbStrings( - rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path, - std::vector< rtl::OUString > * strings) -{ - assert(strings != 0); - RegistryKey subkey; - switch (key.openKey(path, subkey)) { - case REG_NO_ERROR: - break; - case REG_KEY_NOT_EXISTS: - return; - default: - throw css::uno::DeploymentException( - "Failure reading legacy rdb file " + uri, - static_cast< cppu::OWeakObject * >(this)); - } - rtl::OUString prefix(subkey.getName() + "/"); - RegistryKeyNames names; - if (subkey.getKeyNames(rtl::OUString(), names) != REG_NO_ERROR) { - throw css::uno::DeploymentException( - "Failure reading legacy rdb file " + uri, - static_cast< cppu::OWeakObject * >(this)); - } - for (sal_uInt32 i = 0; i != names.getLength(); ++i) { - assert(names.getElement(i).match(prefix)); - strings->push_back(names.getElement(i).copy(prefix.getLength())); - } -} - -void ServiceManager::insertRdbFiles( - std::vector< rtl::OUString > const & uris, - css::uno::Reference< css::uno::XComponentContext > const & alienContext) -{ - Data extra; - for (std::vector< rtl::OUString >::const_iterator i(uris.begin()); - i != uris.end(); ++i) - { - try { - Parser(*i, alienContext, &extra); - } catch (css::container::NoSuchElementException &) { - throw css::lang::IllegalArgumentException( - *i + ": no such file", static_cast< cppu::OWeakObject * >(this), - 0); - } catch (css::registry::InvalidRegistryException & e) { - throw css::lang::IllegalArgumentException( - "InvalidRegistryException: " + e.Message, - static_cast< cppu::OWeakObject * >(this), 0); - } - } - insertExtraData(extra); -} - -void ServiceManager::insertLegacyFactory( - css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo) -{ - assert(factoryInfo.is()); - rtl::OUString name(factoryInfo->getImplementationName()); - css::uno::Reference< css::lang::XSingleComponentFactory > f1( - factoryInfo, css::uno::UNO_QUERY); - css::uno::Reference< css::lang::XSingleServiceFactory > f2; - if (!f1.is()) { - f2 = css::uno::Reference< css::lang::XSingleServiceFactory >( - factoryInfo, css::uno::UNO_QUERY); - } - css::uno::Reference< css::lang::XComponent > comp( - factoryInfo, css::uno::UNO_QUERY); - boost::shared_ptr< Implementation > impl( - new Implementation(name, f1, f2, comp)); - Data extra; - if (!name.isEmpty()) { - extra.namedImplementations.insert( - NamedImplementations::value_type(name, impl)); - } - extra.dynamicImplementations.insert( - DynamicImplementations::value_type(factoryInfo, impl)); - css::uno::Sequence< rtl::OUString > services( - factoryInfo->getSupportedServiceNames()); - for (sal_Int32 i = 0; i != services.getLength(); ++i) { - impl->info->services.push_back(services[i]); - extra.services[services[i]].push_back(impl); - } - if (insertExtraData(extra) && comp.is()) { - comp->addEventListener(this); - } -} - -bool ServiceManager::insertExtraData(Data const & extra) { - { - osl::MutexGuard g(rBHelper.rMutex); - if (isDisposed()) { - return false; - } - for (NamedImplementations::const_iterator i( - extra.namedImplementations.begin()); - i != extra.namedImplementations.end(); ++i) - { - if (data_.namedImplementations.find(i->first) - != data_.namedImplementations.end()) - { - throw css::lang::IllegalArgumentException( - "Insert duplicate implementation name " + i->first, - static_cast< cppu::OWeakObject * >(this), 0); - } - } - for (DynamicImplementations::const_iterator i( - extra.dynamicImplementations.begin()); - i != extra.dynamicImplementations.end(); ++i) - { - if (data_.dynamicImplementations.find(i->first) - != data_.dynamicImplementations.end()) - { - throw css::lang::IllegalArgumentException( - "Insert duplicate factory object", - static_cast< cppu::OWeakObject * >(this), 0); - } - } - //TODO: The below leaves data_ in an inconsistent state upon exceptions: - data_.namedImplementations.insert( - extra.namedImplementations.begin(), - extra.namedImplementations.end()); - data_.dynamicImplementations.insert( - extra.dynamicImplementations.begin(), - extra.dynamicImplementations.end()); - insertImplementationMap(&data_.services, extra.services); - insertImplementationMap(&data_.singletons, extra.singletons); - } - //TODO: Updating the component context singleton data should be part of the - // atomic service manager update: - if (!extra.singletons.empty()) { - assert(context_.is()); - css::uno::Reference< css::container::XNameContainer > cont( - context_, css::uno::UNO_QUERY_THROW); - for (ImplementationMap::const_iterator i(extra.singletons.begin()); - i != extra.singletons.end(); ++i) - { - rtl::OUString name("/singletons/" + i->first); - //TODO: Update should be atomic: - try { - cont->removeByName(name + "/arguments"); - } catch (const css::container::NoSuchElementException &) {} - assert(!i->second.empty()); - assert(i->second[0].get() != 0); - SAL_INFO_IF( - i->second.size() > 1, "cppuhelper", - "Arbitrarily chosing " << i->second[0]->info->name - << " among multiple implementations for singleton " - << i->first); - try { - cont->insertByName( - name + "/service", css::uno::Any(i->second[0]->info->name)); - } catch (css::container::ElementExistException &) { - cont->replaceByName( - name + "/service", css::uno::Any(i->second[0]->info->name)); - } - try { - cont->insertByName(name, css::uno::Any()); - } catch (css::container::ElementExistException &) { - SAL_INFO("cppuhelper", "Overwriting singleton " << i->first); - cont->replaceByName(name, css::uno::Any()); - } - } - } - return true; -} - -void ServiceManager::removeRdbFiles(std::vector< rtl::OUString > const & uris) { - // The underlying data structures make this function somewhat inefficient, - // but the assumption is that it is rarely called (and that if it is called, - // it is called with a uris vector of size one): - std::vector< boost::shared_ptr< Implementation > > clear; - { - osl::MutexGuard g(rBHelper.rMutex); - for (std::vector< rtl::OUString >::const_iterator i(uris.begin()); - i != uris.end(); ++i) - { - for (NamedImplementations::iterator j( - data_.namedImplementations.begin()); - j != data_.namedImplementations.end();) - { - assert(j->second.get() != 0); - if (j->second->info->rdbFile == *i) { - clear.push_back(j->second); - //TODO: The below leaves data_ in an inconsistent state upon - // exceptions: - removeFromImplementationMap( - &data_.services, j->second->info->services, j->second); - removeFromImplementationMap( - &data_.singletons, j->second->info->singletons, - j->second); - data_.namedImplementations.erase(j++); - } else { - ++j; - } - } - } - } - //TODO: Update the component context singleton data -} - -bool ServiceManager::removeLegacyFactory( - css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo, - bool removeListener) -{ - assert(factoryInfo.is()); - boost::shared_ptr< Implementation > clear; - css::uno::Reference< css::lang::XComponent > comp; - { - osl::MutexGuard g(rBHelper.rMutex); - DynamicImplementations::iterator i( - data_.dynamicImplementations.find(factoryInfo)); - if (i == data_.dynamicImplementations.end()) { - return isDisposed(); - } - assert(i->second.get() != 0); - clear = i->second; - //TODO: The below leaves data_ in an inconsistent state upon exceptions: - removeFromImplementationMap( - &data_.services, i->second->info->services, i->second); - removeFromImplementationMap( - &data_.singletons, i->second->info->singletons, i->second); - if (!i->second->info->name.isEmpty()) { - data_.namedImplementations.erase(i->second->info->name); - } - data_.dynamicImplementations.erase(i); - if (removeListener) { - comp = i->second->component; - } - } - if (comp.is()) { - removeEventListenerFromComponent(comp); - } - return true; -} - -void ServiceManager::removeImplementation(rtl::OUString name) { - // The underlying data structures make this function somewhat inefficient, - // but the assumption is that it is rarely called: - boost::shared_ptr< Implementation > clear; - { - osl::MutexGuard g(rBHelper.rMutex); - if (isDisposed()) { - return; - } - NamedImplementations::iterator i(data_.namedImplementations.find(name)); - if (i == data_.namedImplementations.end()) { - throw css::container::NoSuchElementException( - "Remove non-inserted implementation " + name, - static_cast< cppu::OWeakObject * >(this)); - } - assert(i->second.get() != 0); - clear = i->second; - //TODO: The below leaves data_ in an inconsistent state upon exceptions: - removeFromImplementationMap( - &data_.services, i->second->info->services, i->second); - removeFromImplementationMap( - &data_.singletons, i->second->info->singletons, i->second); - for (DynamicImplementations::iterator j( - data_.dynamicImplementations.begin()); - j != data_.dynamicImplementations.end(); ++j) - { - if (j->second == i->second) { - data_.dynamicImplementations.erase(j); - break; - } - } - data_.namedImplementations.erase(i); - } -} - -boost::shared_ptr< Implementation > ServiceManager::findServiceImplementation( - css::uno::Reference< css::uno::XComponentContext > const & context, - rtl::OUString const & specifier) -{ - boost::shared_ptr< Implementation > impl; - bool loaded; - { - osl::MutexGuard g(rBHelper.rMutex); - ImplementationMap::const_iterator i(data_.services.find(specifier)); - if (i == data_.services.end()) { - NamedImplementations::const_iterator j( - data_.namedImplementations.find(specifier)); - if (j == data_.namedImplementations.end()) { - SAL_INFO("cppuhelper", "No implementation for " << specifier); - return boost::shared_ptr< Implementation >(); - } - impl = j->second; - } else { - assert(!i->second.empty()); - SAL_INFO_IF( - i->second.size() > 1, "cppuhelper", - "Arbitrarily chosing " << i->second[0]->info->name - << " among multiple implementations for " << i->first); - impl = i->second[0]; - } - assert(impl.get() != 0); - loaded = impl->loaded; - } - //TODO: There is a race here, as the relevant service factory can be removed - // while the mutex is unlocked and loading can thus fail, as the entity from - // which to load can disappear once the service factory is removed. - if (!loaded) { - css::uno::Reference< css::lang::XSingleComponentFactory > f1; - css::uno::Reference< css::lang::XSingleServiceFactory > f2; - loadImplementation(context, impl->info, &f1, &f2); - osl::MutexGuard g(rBHelper.rMutex); - if (!(isDisposed() || impl->loaded)) { - impl->loaded = true; - impl->factory1 = f1; - impl->factory2 = f2; - } - } - return impl; -} - -css::uno::Reference< css::uno::XInterface > -FactoryWrapper::createInstanceWithContext( - css::uno::Reference< css::uno::XComponentContext > const & Context) - throw (css::uno::Exception, css::uno::RuntimeException) -{ - loadImplementation(Context); - return factory1_.is() - ? factory1_->createInstanceWithContext(Context) - : factory2_->createInstance(); -} - -css::uno::Reference< css::uno::XInterface > -FactoryWrapper::createInstanceWithArgumentsAndContext( - css::uno::Sequence< css::uno::Any > const & Arguments, - css::uno::Reference< css::uno::XComponentContext > const & Context) - throw (css::uno::Exception, css::uno::RuntimeException) -{ - loadImplementation(Context); - return factory1_.is() - ? factory1_->createInstanceWithArgumentsAndContext(Arguments, Context) - : factory2_->createInstanceWithArguments(Arguments); -} - -css::uno::Reference< css::uno::XInterface > FactoryWrapper::createInstance() - throw (css::uno::Exception, css::uno::RuntimeException) -{ - loadImplementation(manager_->getContext()); - return factory1_.is() - ? factory1_->createInstanceWithContext(manager_->getContext()) - : factory2_->createInstance(); -} - -css::uno::Reference< css::uno::XInterface > -FactoryWrapper::createInstanceWithArguments( - css::uno::Sequence< css::uno::Any > const & Arguments) - throw (css::uno::Exception, css::uno::RuntimeException) -{ - loadImplementation(manager_->getContext()); - return factory1_.is() - ? factory1_->createInstanceWithArgumentsAndContext( - Arguments, manager_->getContext()) - : factory2_->createInstanceWithArguments(Arguments); -} - -rtl::OUString FactoryWrapper::getImplementationName() - throw (css::uno::RuntimeException) -{ - return info_->name; -} - -sal_Bool FactoryWrapper::supportsService(rtl::OUString const & ServiceName) - throw (css::uno::RuntimeException) -{ - return cppu::supportsService(this, ServiceName); -} - -css::uno::Sequence< rtl::OUString > FactoryWrapper::getSupportedServiceNames() - throw (css::uno::RuntimeException) -{ - if (info_->services.size() > static_cast< sal_uInt32 >(SAL_MAX_INT32)) { - throw css::uno::RuntimeException( - "Implementation " + info_->name + " supports too many services", - static_cast< cppu::OWeakObject * >(this)); - } - css::uno::Sequence< rtl::OUString > names( - static_cast< sal_Int32 >(info_->services.size())); - sal_Int32 i = 0; - for (std::vector< rtl::OUString >::const_iterator j( - info_->services.begin()); - j != info_->services.end(); ++j) - { - names[i++] = *j; - } - return names; -} - -void FactoryWrapper::loadImplementation( - css::uno::Reference< css::uno::XComponentContext > const & context) -{ - { - osl::MutexGuard g(mutex_); - if (loaded_) { - return; - } - } - css::uno::Reference< css::lang::XSingleComponentFactory > f1; - css::uno::Reference< css::lang::XSingleServiceFactory > f2; - //TODO: There is a race here, as the relevant service factory can already - // have been removed and loading can thus fail, as the entity from which to - // load can disappear once the service factory is removed: - manager_->loadImplementation(context, info_, &f1, &f2); - if (!(f1.is() || f2.is())) { - throw css::uno::DeploymentException( - "Implementation " + info_->name + " does not provide a factory", - static_cast< cppu::OWeakObject * >(this)); - } - osl::MutexGuard g(mutex_); - if (!loaded_) { - loaded_ = true; - factory1_ = f1; - factory2_ = f2; - } -} - css::uno::Reference< css::uno::XComponentContext > bootstrapComponentContext( css::uno::Reference< css::registry::XSimpleRegistry > const & typeRegistry, rtl::OUString const & serviceUris, rtl::Bootstrap const & bootstrap) { - rtl::Reference< ServiceManager > smgr(new ServiceManager(serviceUris)); + rtl::Reference< cppuhelper::ServiceManager > smgr( + new cppuhelper::ServiceManager(serviceUris)); cppu::ContextEntry_Init entry; std::vector< cppu::ContextEntry_Init > context_values; context_values.push_back( @@ -2003,8 +79,9 @@ css::uno::Reference< css::uno::XComponentContext > bootstrapComponentContext( css::uno::makeAny( cppuhelper::detail::create_bootstrap_macro_expander_factory()), true)); - Data const & data = smgr->getData(); - for (ImplementationMap::const_iterator i(data.singletons.begin()); + cppuhelper::ServiceManager::Data const & data = smgr->getData(); + for (cppuhelper::ServiceManager::Data::ImplementationMap::const_iterator i( + data.singletons.begin()); i != data.singletons.end(); ++i) { assert(!i->second.empty()); @@ -2057,118 +134,6 @@ rtl::OUString getBootstrapVariable( return v; } -css::uno::Reference< css::registry::XSimpleRegistry > readTypeRdbFile( - rtl::OUString const & uri, bool optional, - css::uno::Reference< css::registry::XSimpleRegistry > const & lastRegistry, - css::uno::Reference< css::lang::XSingleServiceFactory > const & - simpleRegistryFactory, - css::uno::Reference< css::lang::XSingleServiceFactory > const & - nestedRegistryFactory) -{ - assert(simpleRegistryFactory.is() && nestedRegistryFactory.is()); - try { - css::uno::Reference< css::registry::XSimpleRegistry > simple( - simpleRegistryFactory->createInstance(), css::uno::UNO_QUERY_THROW); - simple->open(uri, true, false); - if (lastRegistry.is()) { - css::uno::Reference< css::registry::XSimpleRegistry > nested( - nestedRegistryFactory->createInstance(), - css::uno::UNO_QUERY_THROW); - css::uno::Sequence< css::uno::Any > args(2); - args[0] <<= lastRegistry; - args[1] <<= simple; - css::uno::Reference< css::lang::XInitialization >( - nested, css::uno::UNO_QUERY_THROW)-> - initialize(args); - return nested; - } else { - return simple; - } - } catch (css::registry::InvalidRegistryException & e) { - if (!optional) { - throw css::uno::DeploymentException( - "Invalid registry " + uri + ":" + e.Message, - css::uno::Reference< css::uno::XInterface >()); - } - SAL_INFO("cppuhelper", "Ignored optional " << uri); - return lastRegistry; - } -} - -css::uno::Reference< css::registry::XSimpleRegistry > readTypeRdbDirectory( - rtl::OUString const & uri, bool optional, - css::uno::Reference< css::registry::XSimpleRegistry > const & lastRegistry, - css::uno::Reference< css::lang::XSingleServiceFactory > const & - simpleRegistryFactory, - css::uno::Reference< css::lang::XSingleServiceFactory > const & - nestedRegistryFactory) -{ - assert(simpleRegistryFactory.is() && nestedRegistryFactory.is()); - osl::Directory dir(uri); - switch (dir.open()) { - case osl::FileBase::E_None: - break; - case osl::FileBase::E_NOENT: - if (optional) { - SAL_INFO("cppuhelper", "Ignored optional " << uri); - return lastRegistry; - } - // fall through - default: - throw css::uno::DeploymentException( - "Cannot open directory " + uri, - css::uno::Reference< css::uno::XInterface >()); - } - css::uno::Reference< css::registry::XSimpleRegistry > last(lastRegistry); - for (;;) { - rtl::OUString fileUri; - if (!nextDirectoryItem(dir, &fileUri)) { - break; - } - last = readTypeRdbFile( - fileUri, optional, last, simpleRegistryFactory, - nestedRegistryFactory); - } - return last; -} - -css::uno::Reference< css::registry::XSimpleRegistry > createTypeRegistry( - rtl::OUString const & uris, rtl::OUString const & libraryDirectoryUri) -{ - css::uno::Reference< css::lang::XMultiComponentFactory > factory( - cppu::bootstrapInitialSF(libraryDirectoryUri)); - css::uno::Reference< css::lang::XSingleServiceFactory > simpleRegs( - cppu::loadSharedLibComponentFactory( - "bootstrap.uno" SAL_DLLEXTENSION, libraryDirectoryUri, - "com.sun.star.comp.stoc.SimpleRegistry", - css::uno::Reference< css::lang::XMultiServiceFactory >( - factory, css::uno::UNO_QUERY_THROW), - css::uno::Reference< css::registry::XRegistryKey >()), - css::uno::UNO_QUERY_THROW); - css::uno::Reference< css::lang::XSingleServiceFactory > nestedRegs( - cppu::loadSharedLibComponentFactory( - "bootstrap.uno" SAL_DLLEXTENSION, libraryDirectoryUri, - "com.sun.star.comp.stoc.NestedRegistry", - css::uno::Reference< css::lang::XMultiServiceFactory >( - factory, css::uno::UNO_QUERY_THROW), - css::uno::Reference< css::registry::XRegistryKey >()), - css::uno::UNO_QUERY_THROW); - css::uno::Reference< css::registry::XSimpleRegistry > reg; - for (sal_Int32 i = 0; i != -1;) { - rtl::OUString uri(uris.getToken(0, ' ', i)); - if (uri.isEmpty()) { - continue; - } - bool optional; - bool directory; - decodeRdbUri(&uri, &optional, &directory); - reg = directory - ? readTypeRdbDirectory(uri, optional, reg, simpleRegs, nestedRegs) - : readTypeRdbFile(uri, optional, reg, simpleRegs, nestedRegs); - } - return reg; -} - } css::uno::Reference< css::uno::XComponentContext > @@ -2182,7 +147,7 @@ cppu::defaultBootstrap_InitialComponentContext(rtl::OUString const & iniUri) css::uno::Reference< css::uno::XInterface >()); } return bootstrapComponentContext( - createTypeRegistry( + cppuhelper::createTypeRegistry( getBootstrapVariable(bs, "UNO_TYPES"), getBootstrapVariable(bs, "URE_INTERNAL_LIB_DIR")), getBootstrapVariable(bs, "UNO_SERVICES"), bs); diff --git a/cppuhelper/source/paths.cxx b/cppuhelper/source/paths.cxx index f6f9ed804296..c5ce22bdbe3b 100644 --- a/cppuhelper/source/paths.cxx +++ b/cppuhelper/source/paths.cxx @@ -19,9 +19,12 @@ #include "sal/config.h" +#include + #include "com/sun/star/uno/DeploymentException.hpp" #include "com/sun/star/uno/Reference.hxx" #include "com/sun/star/uno/XInterface.hpp" +#include "osl/file.hxx" #include "osl/module.hxx" #include "osl/mutex.hxx" #include "rtl/ustring.hxx" @@ -66,4 +69,52 @@ rtl::OUString cppu::getUnoIniUri() { return uri + "/" SAL_CONFIGFILE("uno"); } +bool cppu::nextDirectoryItem(osl::Directory & directory, rtl::OUString * url) { + assert(url != 0); + for (;;) { + osl::DirectoryItem i; + switch (directory.getNextItem(i, SAL_MAX_UINT32)) { + case osl::FileBase::E_None: + break; + case osl::FileBase::E_NOENT: + return false; + default: + throw css::uno::DeploymentException( + "Cannot iterate directory", + css::uno::Reference< css::uno::XInterface >()); + } + osl::FileStatus stat( + osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileName | + osl_FileStatus_Mask_FileURL); + if (i.getFileStatus(stat) != osl::FileBase::E_None) { + throw css::uno::DeploymentException( + "Cannot stat in directory", + css::uno::Reference< css::uno::XInterface >()); + } + if (stat.getFileType() != osl::FileStatus::Directory) { //TODO: symlinks + // Ignore backup files: + rtl::OUString name(stat.getFileName()); + if (!(name.match(".") || name.endsWith("~"))) { + *url = stat.getFileURL(); + return true; + } + } + } +} + +void cppu::decodeRdbUri(rtl::OUString * uri, bool * optional, bool * directory) +{ + assert(uri != 0 && optional != 0 && directory != 0); + *optional = (*uri)[0] == '?'; + if (*optional) { + *uri = uri->copy(1); + } + *directory = uri->getLength() >= 3 && (*uri)[0] == '<' + && (*uri)[uri->getLength() - 2] == '>' + && (*uri)[uri->getLength() - 1] == '*'; + if (*directory) { + *uri = uri->copy(1, uri->getLength() - 3); + } +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/paths.hxx b/cppuhelper/source/paths.hxx index fc6b0a38939d..bba083346b5e 100644 --- a/cppuhelper/source/paths.hxx +++ b/cppuhelper/source/paths.hxx @@ -22,6 +22,7 @@ #include "sal/config.h" +namespace osl { class Directory; } namespace rtl { class OUString; } namespace cppu { @@ -30,6 +31,10 @@ rtl::OUString get_this_libpath(); rtl::OUString getUnoIniUri(); +bool nextDirectoryItem(osl::Directory & directory, rtl::OUString * url); + +void decodeRdbUri(rtl::OUString * uri, bool * optional, bool * directory); + } #endif diff --git a/cppuhelper/source/servicemanager.cxx b/cppuhelper/source/servicemanager.cxx new file mode 100644 index 000000000000..a389fd70f728 --- /dev/null +++ b/cppuhelper/source/servicemanager.cxx @@ -0,0 +1,1650 @@ +/* -*- 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/. + */ + +#include "sal/config.h" + +#include +#include +#include + +#include "boost/noncopyable.hpp" +#include "boost/shared_ptr.hpp" +#include "com/sun/star/beans/NamedValue.hpp" +#include "com/sun/star/beans/PropertyAttribute.hpp" +#include "com/sun/star/container/ElementExistException.hpp" +#include "com/sun/star/container/XEnumeration.hpp" +#include "com/sun/star/container/XNameContainer.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/lang/XSingleComponentFactory.hpp" +#include "com/sun/star/lang/XSingleServiceFactory.hpp" +#include "com/sun/star/loader/XImplementationLoader.hpp" +#include "com/sun/star/registry/InvalidRegistryException.hpp" +#include "com/sun/star/uno/DeploymentException.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "cppuhelper/bootstrap.hxx" +#include "cppuhelper/implbase1.hxx" +#include "cppuhelper/implbase3.hxx" +#include "cppuhelper/shlib.hxx" +#include "cppuhelper/supportsservice.hxx" +#include "osl/file.hxx" +#include "registry/registry.hxx" +#include "rtl/ref.hxx" +#include "rtl/uri.hxx" +#include "rtl/ustring.hxx" +#include "xmlreader/xmlreader.hxx" + +#include "paths.hxx" +#include "servicemanager.hxx" + +namespace { + +void insertImplementationMap( + cppuhelper::ServiceManager::Data::ImplementationMap * destination, + cppuhelper::ServiceManager::Data::ImplementationMap const & source) +{ + assert(destination != 0); + for (cppuhelper::ServiceManager::Data::ImplementationMap::const_iterator i( + source.begin()); + i != source.end(); ++i) + { + std::vector< + boost::shared_ptr< + cppuhelper::ServiceManager::Data::Implementation > > & impls + = (*destination)[i->first]; + impls.insert(impls.end(), i->second.begin(), i->second.end()); + } +} + +void removeFromImplementationMap( + cppuhelper::ServiceManager::Data::ImplementationMap * map, + std::vector< rtl::OUString > const & elements, + boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > + const & implementation) +{ + // The underlying data structures make this function somewhat inefficient, + // but the assumption is that it is rarely called: + assert(map != 0); + for (std::vector< rtl::OUString >::const_iterator i(elements.begin()); + i != elements.end(); ++i) + { + cppuhelper::ServiceManager::Data::ImplementationMap::iterator j( + map->find(*i)); + assert(j != map->end()); + std::vector< + boost::shared_ptr< + cppuhelper::ServiceManager::Data::Implementation > >::iterator + k(std::find(j->second.begin(), j->second.end(), implementation)); + assert(k != j->second.end()); + j->second.erase(k); + if (j->second.empty()) { + map->erase(j); + } + } +} + +// For simplicity, this code keeps throwing +// css::registry::InvalidRegistryException for invalid XML rdbs (even though +// that does not fit the exception's name): +class Parser: private boost::noncopyable { +public: + Parser( + rtl::OUString const & uri, + css::uno::Reference< css::uno::XComponentContext > const & alienContext, + cppuhelper::ServiceManager::Data * data); + +private: + void handleComponent(); + + void handleImplementation(); + + void handleService(); + + void handleSingleton(); + + rtl::OUString getNameAttribute(); + + xmlreader::XmlReader reader_; + css::uno::Reference< css::uno::XComponentContext > alienContext_; + cppuhelper::ServiceManager::Data * data_; + rtl::OUString attrLoader_; + rtl::OUString attrUri_; + rtl::OUString attrPrefix_; + rtl::OUString attrImplementation_; + boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > + implementation_; +}; + +Parser::Parser( + rtl::OUString const & uri, + css::uno::Reference< css::uno::XComponentContext > const & alienContext, + cppuhelper::ServiceManager::Data * data): + reader_(uri), alienContext_(alienContext), data_(data) +{ + assert(data != 0); + int ucNsId = reader_.registerNamespaceIri( + xmlreader::Span( + RTL_CONSTASCII_STRINGPARAM( + "http://openoffice.org/2010/uno-components"))); + enum State { + STATE_BEGIN, STATE_END, STATE_COMPONENTS, STATE_COMPONENT_INITIAL, + STATE_COMPONENT, STATE_IMPLEMENTATION, STATE_SERVICE, STATE_SINGLETON }; + for (State state = STATE_BEGIN;;) { + xmlreader::Span name; + int nsId; + xmlreader::XmlReader::Result res = reader_.nextItem( + xmlreader::XmlReader::TEXT_NONE, &name, &nsId); + switch (state) { + case STATE_BEGIN: + if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("components"))) + { + state = STATE_COMPONENTS; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in outer level", + css::uno::Reference< css::uno::XInterface >()); + case STATE_END: + if (res == xmlreader::XmlReader::RESULT_DONE) { + return; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in outer level", + css::uno::Reference< css::uno::XInterface >()); + case STATE_COMPONENTS: + if (res == xmlreader::XmlReader::RESULT_END) { + state = STATE_END; + break; + } + if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("component"))) + { + handleComponent(); + state = STATE_COMPONENT_INITIAL; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in ", + css::uno::Reference< css::uno::XInterface >()); + case STATE_COMPONENT: + if (res == xmlreader::XmlReader::RESULT_END) { + state = STATE_COMPONENTS; + break; + } + // fall through + case STATE_COMPONENT_INITIAL: + if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("implementation"))) + { + handleImplementation(); + state = STATE_IMPLEMENTATION; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in ", + css::uno::Reference< css::uno::XInterface >()); + case STATE_IMPLEMENTATION: + if (res == xmlreader::XmlReader::RESULT_END) { + state = STATE_COMPONENT; + break; + } + if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("service"))) + { + handleService(); + state = STATE_SERVICE; + break; + } + if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId + && name.equals(RTL_CONSTASCII_STRINGPARAM("singleton"))) + { + handleSingleton(); + state = STATE_SINGLETON; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in ", + css::uno::Reference< css::uno::XInterface >()); + case STATE_SERVICE: + if (res == xmlreader::XmlReader::RESULT_END) { + state = STATE_IMPLEMENTATION; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in ", + css::uno::Reference< css::uno::XInterface >()); + case STATE_SINGLETON: + if (res == xmlreader::XmlReader::RESULT_END) { + state = STATE_IMPLEMENTATION; + break; + } + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": unexpected item in ", + css::uno::Reference< css::uno::XInterface >()); + } + } +} + +void Parser::handleComponent() { + attrLoader_ = rtl::OUString(); + attrUri_ = rtl::OUString(); + attrPrefix_ = rtl::OUString(); + xmlreader::Span name; + int nsId; + while (reader_.nextAttribute(&nsId, &name)) { + if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("loader"))) + { + if (!attrLoader_.isEmpty()) { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + + ": has multiple \"loader\" attributes"), + css::uno::Reference< css::uno::XInterface >()); + } + attrLoader_ = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrLoader_.isEmpty()) { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + + ": has empty \"loader\" attribute"), + css::uno::Reference< css::uno::XInterface >()); + } + } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("uri"))) + { + if (!attrUri_.isEmpty()) { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + + ": has multiple \"uri\" attributes"), + css::uno::Reference< css::uno::XInterface >()); + } + attrUri_ = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrUri_.isEmpty()) { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + + ": has empty \"uri\" attribute"), + css::uno::Reference< css::uno::XInterface >()); + } + } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("prefix"))) + { + if (!attrPrefix_.isEmpty()) { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + + ": has multiple \"prefix\" attributes"), + css::uno::Reference< css::uno::XInterface >()); + } + attrPrefix_ = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrPrefix_.isEmpty()) { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + + ": has empty \"prefix\" attribute"), + css::uno::Reference< css::uno::XInterface >()); + } + } else { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + ": unexpected attribute \"" + + name.convertFromUtf8() + "\" in "), + css::uno::Reference< css::uno::XInterface >()); + } + } + if (attrLoader_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": is missing \"loader\" attribute", + css::uno::Reference< css::uno::XInterface >()); + } + if (attrUri_.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": is missing \"uri\" attribute", + css::uno::Reference< css::uno::XInterface >()); + } +#ifndef DISABLE_DYNLOADING + try { + attrUri_ = rtl::Uri::convertRelToAbs(reader_.getUrl(), attrUri_); + } catch (const rtl::MalformedUriException & e) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": bad \"uri\" attribute: " + e.getMessage(), + css::uno::Reference< css::uno::XInterface >()); + } +#endif +} + +void Parser::handleImplementation() { + attrImplementation_ = getNameAttribute(); + implementation_.reset( + new cppuhelper::ServiceManager::Data::Implementation( + attrImplementation_, attrLoader_, attrUri_, attrPrefix_, + alienContext_, reader_.getUrl())); + if (!data_->namedImplementations.insert( + cppuhelper::ServiceManager::Data::NamedImplementations::value_type( + attrImplementation_, implementation_)). + second) + { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + ": duplicate "), + css::uno::Reference< css::uno::XInterface >()); + } +} + +void Parser::handleService() { + rtl::OUString name(getNameAttribute()); + implementation_->info->services.push_back(name); + data_->services[name].push_back(implementation_); +} + +void Parser::handleSingleton() { + rtl::OUString name(getNameAttribute()); + implementation_->info->singletons.push_back(name); + data_->singletons[name].push_back(implementation_); +} + +rtl::OUString Parser::getNameAttribute() { + rtl::OUString attrName; + xmlreader::Span name; + int nsId; + while (reader_.nextAttribute(&nsId, &name)) { + if (nsId == xmlreader::XmlReader::NAMESPACE_NONE + && name.equals(RTL_CONSTASCII_STRINGPARAM("name"))) + { + if (!attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + (reader_.getUrl() + + ": element has multiple \"name\" attributes"), + css::uno::Reference< css::uno::XInterface >()); + } + attrName = reader_.getAttributeValue(false).convertFromUtf8(); + if (attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": element has empty \"name\" attribute", + css::uno::Reference< css::uno::XInterface >()); + } + } else { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": expected element attribute \"name\"", + css::uno::Reference< css::uno::XInterface >()); + } + } + if (attrName.isEmpty()) { + throw css::registry::InvalidRegistryException( + reader_.getUrl() + ": element is missing \"name\" attribute", + css::uno::Reference< css::uno::XInterface >()); + } + return attrName; +} + +class ContentEnumeration: + public cppu::WeakImplHelper1< css::container::XEnumeration >, + private boost::noncopyable +{ +public: + explicit ContentEnumeration(std::vector< css::uno::Any > const & factories): + factories_(factories), iterator_(factories_.begin()) {} + +private: + virtual ~ContentEnumeration() {} + + virtual sal_Bool SAL_CALL hasMoreElements() + throw (css::uno::RuntimeException); + + virtual css::uno::Any SAL_CALL nextElement() + throw ( + css::container::NoSuchElementException, + css::lang::WrappedTargetException, css::uno::RuntimeException); + + osl::Mutex mutex_; + std::vector< css::uno::Any > factories_; + std::vector< css::uno::Any >::const_iterator iterator_; +}; + +sal_Bool ContentEnumeration::hasMoreElements() + throw (css::uno::RuntimeException) +{ + osl::MutexGuard g(mutex_); + return iterator_ != factories_.end(); +} + +css::uno::Any ContentEnumeration::nextElement() + throw ( + css::container::NoSuchElementException, + css::lang::WrappedTargetException, css::uno::RuntimeException) +{ + osl::MutexGuard g(mutex_); + if (iterator_ == factories_.end()) { + throw css::container::NoSuchElementException( + "Bootstrap service manager service enumerator has no more elements", + static_cast< cppu::OWeakObject * >(this)); + } + return *iterator_++; +} + +css::beans::Property getDefaultContextProperty() { + return css::beans::Property( + "DefaultContext", -1, + cppu::UnoType< css::uno::XComponentContext >::get(), + css::beans::PropertyAttribute::READONLY); +} + +class FactoryWrapper: + public cppu::WeakImplHelper3< + css::lang::XSingleComponentFactory, css::lang::XSingleServiceFactory, + css::lang::XServiceInfo >, + private boost::noncopyable +{ +public: + FactoryWrapper( + rtl::Reference< cppuhelper::ServiceManager > const & manager, + boost::shared_ptr< + cppuhelper::ServiceManager::Data::ImplementationInfo > const & + info): + manager_(manager), info_(info), loaded_(false) + { assert(manager.is() && info.get() != 0); } + +private: + virtual ~FactoryWrapper() {} + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithContext( + css::uno::Reference< css::uno::XComponentContext > const & Context) + throw (css::uno::Exception, css::uno::RuntimeException); + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArgumentsAndContext( + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) + throw (css::uno::Exception, css::uno::RuntimeException); + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstance() throw (css::uno::Exception, css::uno::RuntimeException); + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArguments( + css::uno::Sequence< css::uno::Any > const & Arguments) + throw (css::uno::Exception, css::uno::RuntimeException); + + virtual rtl::OUString SAL_CALL getImplementationName() + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) + throw (css::uno::RuntimeException); + + virtual css::uno::Sequence< rtl::OUString > SAL_CALL + getSupportedServiceNames() throw (css::uno::RuntimeException); + + void loadImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context); + + rtl::Reference< cppuhelper::ServiceManager > manager_; + boost::shared_ptr< cppuhelper::ServiceManager::Data::ImplementationInfo > + info_; + + osl::Mutex mutex_; + bool loaded_; + css::uno::Reference< css::lang::XSingleComponentFactory > factory1_; + css::uno::Reference< css::lang::XSingleServiceFactory > factory2_; +}; + +css::uno::Reference< css::uno::XInterface > +FactoryWrapper::createInstanceWithContext( + css::uno::Reference< css::uno::XComponentContext > const & Context) + throw (css::uno::Exception, css::uno::RuntimeException) +{ + loadImplementation(Context); + return factory1_.is() + ? factory1_->createInstanceWithContext(Context) + : factory2_->createInstance(); +} + +css::uno::Reference< css::uno::XInterface > +FactoryWrapper::createInstanceWithArgumentsAndContext( + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) + throw (css::uno::Exception, css::uno::RuntimeException) +{ + loadImplementation(Context); + return factory1_.is() + ? factory1_->createInstanceWithArgumentsAndContext(Arguments, Context) + : factory2_->createInstanceWithArguments(Arguments); +} + +css::uno::Reference< css::uno::XInterface > FactoryWrapper::createInstance() + throw (css::uno::Exception, css::uno::RuntimeException) +{ + loadImplementation(manager_->getContext()); + return factory1_.is() + ? factory1_->createInstanceWithContext(manager_->getContext()) + : factory2_->createInstance(); +} + +css::uno::Reference< css::uno::XInterface > +FactoryWrapper::createInstanceWithArguments( + css::uno::Sequence< css::uno::Any > const & Arguments) + throw (css::uno::Exception, css::uno::RuntimeException) +{ + loadImplementation(manager_->getContext()); + return factory1_.is() + ? factory1_->createInstanceWithArgumentsAndContext( + Arguments, manager_->getContext()) + : factory2_->createInstanceWithArguments(Arguments); +} + +rtl::OUString FactoryWrapper::getImplementationName() + throw (css::uno::RuntimeException) +{ + return info_->name; +} + +sal_Bool FactoryWrapper::supportsService(rtl::OUString const & ServiceName) + throw (css::uno::RuntimeException) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< rtl::OUString > FactoryWrapper::getSupportedServiceNames() + throw (css::uno::RuntimeException) +{ + if (info_->services.size() > static_cast< sal_uInt32 >(SAL_MAX_INT32)) { + throw css::uno::RuntimeException( + "Implementation " + info_->name + " supports too many services", + static_cast< cppu::OWeakObject * >(this)); + } + css::uno::Sequence< rtl::OUString > names( + static_cast< sal_Int32 >(info_->services.size())); + sal_Int32 i = 0; + for (std::vector< rtl::OUString >::const_iterator j( + info_->services.begin()); + j != info_->services.end(); ++j) + { + names[i++] = *j; + } + return names; +} + +void FactoryWrapper::loadImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context) +{ + { + osl::MutexGuard g(mutex_); + if (loaded_) { + return; + } + } + css::uno::Reference< css::lang::XSingleComponentFactory > f1; + css::uno::Reference< css::lang::XSingleServiceFactory > f2; + //TODO: There is a race here, as the relevant service factory can already + // have been removed and loading can thus fail, as the entity from which to + // load can disappear once the service factory is removed: + manager_->loadImplementation(context, info_, &f1, &f2); + if (!(f1.is() || f2.is())) { + throw css::uno::DeploymentException( + "Implementation " + info_->name + " does not provide a factory", + static_cast< cppu::OWeakObject * >(this)); + } + osl::MutexGuard g(mutex_); + if (!loaded_) { + loaded_ = true; + factory1_ = f1; + factory2_ = f2; + } +} + +} + +void cppuhelper::ServiceManager::loadImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context, + boost::shared_ptr< Data::ImplementationInfo > const & info, + css::uno::Reference< css::lang::XSingleComponentFactory > * factory1, + css::uno::Reference< css::lang::XSingleServiceFactory > * factory2) +{ + assert( + info.get() != 0 && factory1 != 0 && !factory1->is() && factory2 != 0 + && !factory2->is()); + rtl::OUString uri; + try { + uri = cppu::bootstrap_expandUri(info->uri); + } catch (css::lang::IllegalArgumentException & e) { + throw css::uno::DeploymentException( + "Cannot expand URI" + info->uri + ": " + e.Message, + static_cast< cppu::OWeakObject * >(this)); + } + css::uno::Reference< css::uno::XInterface > f0; + // Shortcut loading via SharedLibrary loader, to pass in prefix argument + // (which the loader's activate implementation would normally obtain through + // the legacy xKey argument): + if (!info->alienContext.is() + && info->loader == "com.sun.star.loader.SharedLibrary") + { + rtl::OUString prefix(info->prefix); + if (!prefix.isEmpty()) { + prefix += "_"; + } + f0 = cppu::loadSharedLibComponentFactory( + uri, rtl::OUString(), info->name, this, + css::uno::Reference< css::registry::XRegistryKey >(), prefix); + } else { + SAL_INFO_IF( + !info->prefix.isEmpty(), "cppuhelper", + "Loader " << info->loader << " and non-empty prefix " + << info->prefix); + css::uno::Reference< css::uno::XComponentContext > ctxt; + css::uno::Reference< css::lang::XMultiComponentFactory > smgr; + if (info->alienContext.is()) { + ctxt = info->alienContext; + smgr = css::uno::Reference< css::lang::XMultiComponentFactory >( + ctxt->getServiceManager(), css::uno::UNO_SET_THROW); + } else { + assert(context.is()); + ctxt = context; + smgr = this; + } + css::uno::Reference< css::loader::XImplementationLoader > loader( + smgr->createInstanceWithContext(info->loader, ctxt), + css::uno::UNO_QUERY_THROW); + f0 = loader->activate( + info->name, rtl::OUString(), uri, + css::uno::Reference< css::registry::XRegistryKey >()); + } + factory1->set(f0, css::uno::UNO_QUERY); + if (!factory1->is()) { + factory2->set(f0, css::uno::UNO_QUERY); + } +} + +rtl::OUString cppuhelper::ServiceManager::getImplementationName() + throw (css::uno::RuntimeException) +{ + return rtl::OUString( + "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager"); +} + +sal_Bool cppuhelper::ServiceManager::supportsService( + rtl::OUString const & ServiceName) + throw (css::uno::RuntimeException) +{ + return cppu::supportsService(this, ServiceName); +} + +css::uno::Sequence< rtl::OUString > +cppuhelper::ServiceManager::getSupportedServiceNames() + throw (css::uno::RuntimeException) +{ + css::uno::Sequence< rtl::OUString > names(2); + names[0] = "com.sun.star.lang.MultiServiceFactory"; + names[1] = "com.sun.star.lang.ServiceManager"; + return names; +} + +css::uno::Reference< css::uno::XInterface > +cppuhelper::ServiceManager::createInstance( + rtl::OUString const & aServiceSpecifier) + throw (css::uno::Exception, css::uno::RuntimeException) +{ + assert(context_.is()); + return createInstanceWithContext(aServiceSpecifier, context_); +} + +css::uno::Reference< css::uno::XInterface > +cppuhelper::ServiceManager::createInstanceWithArguments( + rtl::OUString const & ServiceSpecifier, + css::uno::Sequence< css::uno::Any > const & Arguments) + throw (css::uno::Exception, css::uno::RuntimeException) +{ + assert(context_.is()); + return createInstanceWithArgumentsAndContext( + ServiceSpecifier, Arguments, context_); +} + +css::uno::Sequence< rtl::OUString > +cppuhelper::ServiceManager::getAvailableServiceNames() + throw (css::uno::RuntimeException) +{ + osl::MutexGuard g(rBHelper.rMutex); + if (isDisposed()) { + return css::uno::Sequence< rtl::OUString >(); + } + Data::ImplementationMap::size_type n = data_.services.size(); + if (n > static_cast< sal_uInt32 >(SAL_MAX_INT32)) { + throw css::uno::RuntimeException( + "getAvailableServiceNames: too many services", + static_cast< cppu::OWeakObject * >(this)); + } + css::uno::Sequence< rtl::OUString > names(static_cast< sal_Int32 >(n)); + sal_Int32 i = 0; + for (Data::ImplementationMap::const_iterator j(data_.services.begin()); + j != data_.services.end(); ++j) + { + names[i++] = j->first; + } + assert(i == names.getLength()); + return names; +} + +css::uno::Reference< css::uno::XInterface > +cppuhelper::ServiceManager::createInstanceWithContext( + rtl::OUString const & aServiceSpecifier, + css::uno::Reference< css::uno::XComponentContext > const & Context) + throw (css::uno::Exception, css::uno::RuntimeException) +{ + boost::shared_ptr< Data::Implementation > impl( + findServiceImplementation(Context, aServiceSpecifier)); + if (impl.get() == 0) { + return css::uno::Reference< css::uno::XInterface >(); + } + if (impl->factory1.is()) { + return impl->factory1->createInstanceWithContext(Context); + } + if (impl->factory2.is()) { + return impl->factory2->createInstance(); + } + throw css::uno::DeploymentException( + "Implementation " + impl->info->name + " does not provide a factory", + static_cast< cppu::OWeakObject * >(this)); +} + +css::uno::Reference< css::uno::XInterface > +cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext( + rtl::OUString const & ServiceSpecifier, + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) + throw (css::uno::Exception, css::uno::RuntimeException) +{ + boost::shared_ptr< Data::Implementation > impl( + findServiceImplementation(Context, ServiceSpecifier)); + if (impl.get() == 0) { + return css::uno::Reference< css::uno::XInterface >(); + } + if (impl->factory1.is()) { + return impl->factory1->createInstanceWithArgumentsAndContext( + Arguments, Context); + } + if (impl->factory2.is()) { + return impl->factory2->createInstanceWithArguments(Arguments); + } + throw css::uno::DeploymentException( + "Implementation " + impl->info->name + " does not provide a factory", + static_cast< cppu::OWeakObject * >(this)); +} + +css::uno::Type cppuhelper::ServiceManager::getElementType() + throw (css::uno::RuntimeException) +{ + return css::uno::Type(); +} + +sal_Bool cppuhelper::ServiceManager::hasElements() + throw (css::uno::RuntimeException) +{ + osl::MutexGuard g(rBHelper.rMutex); + return + !(data_.namedImplementations.empty() + && data_.dynamicImplementations.empty()); +} + +css::uno::Reference< css::container::XEnumeration > +cppuhelper::ServiceManager::createEnumeration() + throw (css::uno::RuntimeException) +{ + throw css::uno::RuntimeException( + "ServiceManager createEnumeration: method not supported", + static_cast< cppu::OWeakObject * >(this)); +} + +sal_Bool cppuhelper::ServiceManager::has(css::uno::Any const &) + throw (css::uno::RuntimeException) +{ + throw css::uno::RuntimeException( + "ServiceManager has: method not supported", + static_cast< cppu::OWeakObject * >(this)); +} + +void cppuhelper::ServiceManager::insert(css::uno::Any const & aElement) + throw ( + css::lang::IllegalArgumentException, + css::container::ElementExistException, css::uno::RuntimeException) +{ + css::uno::Sequence< css::beans::NamedValue > args; + if (aElement >>= args) { + std::vector< rtl::OUString > uris; + css::uno::Reference< css::uno::XComponentContext > alienContext; + for (sal_Int32 i = 0; i < args.getLength(); ++i) { + if (args[i].Name == "uri") { + rtl::OUString uri; + if (!(args[i].Value >>= uri)) { + throw css::lang::IllegalArgumentException( + "Bad uri argument", + static_cast< cppu::OWeakObject * >(this), 0); + } + uris.push_back(uri); + } else if (args[i].Name == "component-context") { + if (alienContext.is()) { + throw css::lang::IllegalArgumentException( + "Multiple component-context arguments", + static_cast< cppu::OWeakObject * >(this), 0); + } + if (!(args[i].Value >>= alienContext) || !alienContext.is()) { + throw css::lang::IllegalArgumentException( + "Bad component-context argument", + static_cast< cppu::OWeakObject * >(this), 0); + } + } else { + throw css::lang::IllegalArgumentException( + "Bad argument " + args[i].Name, + static_cast< cppu::OWeakObject * >(this), 0); + } + } + insertRdbFiles(uris, alienContext); + return; + } + css::uno::Reference< css::lang::XServiceInfo > info; + if ((aElement >>= info) && info.is()) { + insertLegacyFactory(info); + return; + } +// At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in +// module languagetool) contain an (actively registered) factory that does not +// implement XServiceInfo (see "SingletonFactory should +// implement XServiceInfo"); the old OServiceManager::insert +// (stoc/source/servicemanager/servicemanager.cxx) silently did not add such +// broken factories to its m_ImplementationNameMap, so ignore them here for +// backwards compatibility of live-insertion of extensions, too. + +// (The plan was that this warning would go away (and we would do the +// throw instead) for the incompatible LO 4, but we changed our mind): + css::uno::Reference< css::lang::XSingleComponentFactory > legacy; + if ((aElement >>= legacy) && legacy.is()) { + SAL_WARN( + "cppuhelper", + "Ignored XSingleComponentFactory not implementing XServiceInfo"); + return; + } + + throw css::lang::IllegalArgumentException( + "Bad insert element", static_cast< cppu::OWeakObject * >(this), 0); +} + +void cppuhelper::ServiceManager::remove(css::uno::Any const & aElement) + throw ( + css::lang::IllegalArgumentException, + css::container::NoSuchElementException, css::uno::RuntimeException) +{ + css::uno::Sequence< css::beans::NamedValue > args; + if (aElement >>= args) { + std::vector< rtl::OUString > uris; + for (sal_Int32 i = 0; i < args.getLength(); ++i) { + if (args[i].Name == "uri") { + rtl::OUString uri; + if (!(args[i].Value >>= uri)) { + throw css::lang::IllegalArgumentException( + "Bad uri argument", + static_cast< cppu::OWeakObject * >(this), 0); + } + uris.push_back(uri); + } else { + throw css::lang::IllegalArgumentException( + "Bad argument " + args[i].Name, + static_cast< cppu::OWeakObject * >(this), 0); + } + } + removeRdbFiles(uris); + return; + } + css::uno::Reference< css::lang::XServiceInfo > info; + if ((aElement >>= info) && info.is()) { + if (!removeLegacyFactory(info, true)) { + throw css::container::NoSuchElementException( + "Remove non-inserted factory object", + static_cast< cppu::OWeakObject * >(this)); + } + return; + } + rtl::OUString impl; + if (aElement >>= impl) { + // For live-removal of extensions: + removeImplementation(impl); + return; + } + throw css::lang::IllegalArgumentException( + "Bad remove element", static_cast< cppu::OWeakObject * >(this), 0); +} + +css::uno::Reference< css::container::XEnumeration > +cppuhelper::ServiceManager::createContentEnumeration( + rtl::OUString const & aServiceName) + throw (css::uno::RuntimeException) +{ + std::vector< boost::shared_ptr< Data::Implementation > > impls; + { + osl::MutexGuard g(rBHelper.rMutex); + Data::ImplementationMap::const_iterator i( + data_.services.find(aServiceName)); + if (i != data_.services.end()) { + impls = i->second; + } + } + std::vector< css::uno::Any > factories; + for (std::vector< + boost::shared_ptr< Data::Implementation > >::const_iterator i( + impls.begin()); + i != impls.end(); ++i) + { + Data::Implementation * impl = i->get(); + assert(impl != 0); + { + osl::MutexGuard g(rBHelper.rMutex); + if (isDisposed()) { + factories.clear(); + break; + } + if (!impl->loaded) { + // Postpone actual factory instantiation as long as possible (so + // that e.g. opening LO's "Tools - Macros" menu does not try to + // instantiate a JVM, which can lead to a synchronous error + // dialog when no JVM is specified, and showing the dialog while + // hovering over a menu can cause trouble): + impl->factory1 = new FactoryWrapper(this, impl->info); + impl->loaded = true; + } + } + if (impl->factory1.is()) { + factories.push_back(css::uno::makeAny(impl->factory1)); + } else if (impl->factory2.is()) { + factories.push_back(css::uno::makeAny(impl->factory2)); + } else { + throw css::uno::DeploymentException( + ("Implementation " + impl->info->name + + " does not provide a factory"), + static_cast< cppu::OWeakObject * >(this)); + } + } + return new ContentEnumeration(factories); +} + +css::uno::Reference< css::beans::XPropertySetInfo > +cppuhelper::ServiceManager::getPropertySetInfo() + throw (css::uno::RuntimeException) +{ + return this; +} + +void cppuhelper::ServiceManager::setPropertyValue( + rtl::OUString const & aPropertyName, css::uno::Any const &) + throw ( + css::beans::UnknownPropertyException, css::beans::PropertyVetoException, + css::lang::IllegalArgumentException, css::lang::WrappedTargetException, + css::uno::RuntimeException) +{ + if (aPropertyName == "DefaultContext") { + throw css::beans::PropertyVetoException( + aPropertyName, static_cast< cppu::OWeakObject * >(this)); + } else { + throw css::beans::UnknownPropertyException( + aPropertyName, static_cast< cppu::OWeakObject * >(this)); + } +} + +css::uno::Any cppuhelper::ServiceManager::getPropertyValue( + rtl::OUString const & PropertyName) + throw ( + css::beans::UnknownPropertyException, css::lang::WrappedTargetException, + css::uno::RuntimeException) +{ + if (PropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + PropertyName, static_cast< cppu::OWeakObject * >(this)); + } + assert(context_.is()); + return css::uno::makeAny(context_); +} + +void cppuhelper::ServiceManager::addPropertyChangeListener( + rtl::OUString const & aPropertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & + xListener) + throw ( + css::beans::UnknownPropertyException, css::lang::WrappedTargetException, + css::uno::RuntimeException) +{ + if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + aPropertyName, static_cast< cppu::OWeakObject * >(this)); + } + // DefaultContext does not change, so just treat it as an event listener: + return addEventListener(xListener.get()); +} + +void cppuhelper::ServiceManager::removePropertyChangeListener( + rtl::OUString const & aPropertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & + aListener) + throw ( + css::beans::UnknownPropertyException, css::lang::WrappedTargetException, + css::uno::RuntimeException) +{ + if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + aPropertyName, static_cast< cppu::OWeakObject * >(this)); + } + // DefaultContext does not change, so just treat it as an event listener: + return removeEventListener(aListener.get()); +} + +void cppuhelper::ServiceManager::addVetoableChangeListener( + rtl::OUString const & PropertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & + aListener) + throw ( + css::beans::UnknownPropertyException, css::lang::WrappedTargetException, + css::uno::RuntimeException) +{ + if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + PropertyName, static_cast< cppu::OWeakObject * >(this)); + } + // DefaultContext does not change, so just treat it as an event listener: + return addEventListener(aListener.get()); +} + +void cppuhelper::ServiceManager::removeVetoableChangeListener( + rtl::OUString const & PropertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & + aListener) + throw ( + css::beans::UnknownPropertyException, css::lang::WrappedTargetException, + css::uno::RuntimeException) +{ + if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + PropertyName, static_cast< cppu::OWeakObject * >(this)); + } + // DefaultContext does not change, so just treat it as an event listener: + return removeEventListener(aListener.get()); +} + +css::uno::Sequence< css::beans::Property > +cppuhelper::ServiceManager::getProperties() throw (css::uno::RuntimeException) { + css::uno::Sequence< css::beans::Property > props(1); + props[0] = getDefaultContextProperty(); + return props; +} + +css::beans::Property cppuhelper::ServiceManager::getPropertyByName( + rtl::OUString const & aName) + throw (css::beans::UnknownPropertyException, css::uno::RuntimeException) +{ + if (aName != "DefaultContext") { + throw css::beans::UnknownPropertyException( + aName, static_cast< cppu::OWeakObject * >(this)); + } + return getDefaultContextProperty(); +} + +sal_Bool cppuhelper::ServiceManager::hasPropertyByName( + rtl::OUString const & Name) + throw (css::uno::RuntimeException) +{ + return Name == "DefaultContext"; +} + +void cppuhelper::ServiceManager::disposing( + css::lang::EventObject const & Source) + throw (css::uno::RuntimeException) +{ + removeLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo >( + Source.Source, css::uno::UNO_QUERY_THROW), + false); +} + +void cppuhelper::ServiceManager::disposing() { + std::vector< css::uno::Reference< css::lang::XComponent > > comps; + Data clear; + { + osl::MutexGuard g(rBHelper.rMutex); + for (Data::DynamicImplementations::const_iterator i( + data_.dynamicImplementations.begin()); + i != data_.dynamicImplementations.end(); ++i) + { + assert(i->second.get() != 0); + if (i->second->component.is()) { + comps.push_back(i->second->component); + } + } + data_.namedImplementations.swap(clear.namedImplementations); + data_.dynamicImplementations.swap(clear.dynamicImplementations); + data_.services.swap(clear.services); + data_.singletons.swap(clear.singletons); + } + for (std::vector< + css::uno::Reference< css::lang::XComponent > >::const_iterator i( + comps.begin()); + i != comps.end(); ++i) + { + removeEventListenerFromComponent(*i); + } +} + +void cppuhelper::ServiceManager::removeEventListenerFromComponent( + css::uno::Reference< css::lang::XComponent > const & component) +{ + assert(component.is()); + try { + component->removeEventListener(this); + } catch (css::uno::RuntimeException & e) { + SAL_INFO( + "cppuhelper", + "Ignored removeEventListener RuntimeException " + e.Message); + } +} + +void cppuhelper::ServiceManager::readRdbs(rtl::OUString const & uris) { + for (sal_Int32 i = 0; i != -1;) { + rtl::OUString uri(uris.getToken(0, ' ', i)); + if (uri.isEmpty()) { + continue; + } + bool optional; + bool directory; + cppu::decodeRdbUri(&uri, &optional, &directory); + if (directory) { + readRdbDirectory(uri, optional); + } else { + readRdbFile(uri, optional); + } + } +} + +void cppuhelper::ServiceManager::readRdbDirectory( + rtl::OUString const & uri, bool optional) +{ + osl::Directory dir(uri); + switch (dir.open()) { + case osl::FileBase::E_None: + break; + case osl::FileBase::E_NOENT: + if (optional) { + SAL_INFO("cppuhelper", "Ignored optional " << uri); + return; + } + // fall through + default: + throw css::uno::DeploymentException( + "Cannot open directory " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + for (;;) { + rtl::OUString url; + if (!cppu::nextDirectoryItem(dir, &url)) { + break; + } + readRdbFile(url, false); + } +} + +void cppuhelper::ServiceManager::readRdbFile( + rtl::OUString const & uri, bool optional) +{ + try { + Parser( + uri, css::uno::Reference< css::uno::XComponentContext >(), &data_); + } catch (css::container::NoSuchElementException &) { + if (!optional) { + throw css::uno::DeploymentException( + uri + ": no such file", + static_cast< cppu::OWeakObject * >(this)); + } + SAL_INFO("cppuhelper", "Ignored optional " << uri); + } catch (css::registry::InvalidRegistryException & e) { + if (!readLegacyRdbFile(uri)) { + throw css::uno::DeploymentException( + "InvalidRegistryException: " + e.Message, + static_cast< cppu::OWeakObject * >(this)); + } + } catch (css::uno::RuntimeException &) { + if (!readLegacyRdbFile(uri)) { + throw; + } + } +} + +bool cppuhelper::ServiceManager::readLegacyRdbFile(rtl::OUString const & uri) { + Registry reg; + switch (reg.open(uri, REG_READONLY)) { + case REG_NO_ERROR: + break; + case REG_REGISTRY_NOT_EXISTS: + case REG_INVALID_REGISTRY: + { + // Ignore empty rdb files (which are at least seen by subordinate + // uno processes during extension registration; Registry::open can + // fail on them if mmap(2) returns EINVAL for a zero length): + osl::DirectoryItem item; + if (osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None) { + osl::FileStatus status(osl_FileStatus_Mask_FileSize); + if (item.getFileStatus(status) == osl::FileBase::E_None + && status.getFileSize() == 0) + { + return true; + } + } + } + // fall through + default: + return false; + } + RegistryKey rootKey; + if (reg.openRootKey(rootKey) != REG_NO_ERROR) { + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + RegistryKeyArray impls; + switch (rootKey.openSubKeys("IMPLEMENTATIONS", impls)) { + case REG_NO_ERROR: + break; + case REG_KEY_NOT_EXISTS: + return true; + default: + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + for (sal_uInt32 i = 0; i != impls.getLength(); ++i) { + RegistryKey implKey(impls.getElement(i)); + assert(implKey.getName().match("/IMPLEMENTATIONS/")); + rtl::OUString name( + implKey.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/"))); + boost::shared_ptr< Data::Implementation > impl( + new Data::Implementation( + name, readLegacyRdbString(uri, implKey, "UNO/ACTIVATOR"), + readLegacyRdbString(uri, implKey, "UNO/LOCATION"), + rtl::OUString(), + css::uno::Reference< css::uno::XComponentContext >(), uri)); + if (!data_.namedImplementations.insert( + Data::NamedImplementations::value_type(name, impl)). + second) + { + throw css::registry::InvalidRegistryException( + uri + ": duplicate ", + css::uno::Reference< css::uno::XInterface >()); + } + readLegacyRdbStrings( + uri, implKey, "UNO/SERVICES", &impl->info->services); + for (std::vector< rtl::OUString >::const_iterator j( + impl->info->services.begin()); + j != impl->info->services.end(); ++j) + { + data_.services[*j].push_back(impl); + } + readLegacyRdbStrings( + uri, implKey, "UNO/SINGLETONS", &impl->info->singletons); + for (std::vector< rtl::OUString >::const_iterator j( + impl->info->singletons.begin()); + j != impl->info->singletons.end(); ++j) + { + data_.singletons[*j].push_back(impl); + } + } + return true; +} + +rtl::OUString cppuhelper::ServiceManager::readLegacyRdbString( + rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path) +{ + RegistryKey subkey; + RegValueType t; + sal_uInt32 s(0); + if (key.openKey(path, subkey) != REG_NO_ERROR + || subkey.getValueInfo(rtl::OUString(), &t, &s) != REG_NO_ERROR + || t != RG_VALUETYPE_STRING + || s == 0 || s > static_cast< sal_uInt32 >(SAL_MAX_INT32)) + { + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + rtl::OUString val; + std::vector< char > v(s); // assuming sal_uInt32 fits into vector::size_type + if (subkey.getValue(rtl::OUString(), &v[0]) != REG_NO_ERROR + || v.back() != '\0' + || !rtl_convertStringToUString( + &val.pData, &v[0], static_cast< sal_Int32 >(s - 1), + RTL_TEXTENCODING_UTF8, + (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR + | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR))) + { + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + return val; +} + +void cppuhelper::ServiceManager::readLegacyRdbStrings( + rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path, + std::vector< rtl::OUString > * strings) +{ + assert(strings != 0); + RegistryKey subkey; + switch (key.openKey(path, subkey)) { + case REG_NO_ERROR: + break; + case REG_KEY_NOT_EXISTS: + return; + default: + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + rtl::OUString prefix(subkey.getName() + "/"); + RegistryKeyNames names; + if (subkey.getKeyNames(rtl::OUString(), names) != REG_NO_ERROR) { + throw css::uno::DeploymentException( + "Failure reading legacy rdb file " + uri, + static_cast< cppu::OWeakObject * >(this)); + } + for (sal_uInt32 i = 0; i != names.getLength(); ++i) { + assert(names.getElement(i).match(prefix)); + strings->push_back(names.getElement(i).copy(prefix.getLength())); + } +} + +void cppuhelper::ServiceManager::insertRdbFiles( + std::vector< rtl::OUString > const & uris, + css::uno::Reference< css::uno::XComponentContext > const & alienContext) +{ + Data extra; + for (std::vector< rtl::OUString >::const_iterator i(uris.begin()); + i != uris.end(); ++i) + { + try { + Parser(*i, alienContext, &extra); + } catch (css::container::NoSuchElementException &) { + throw css::lang::IllegalArgumentException( + *i + ": no such file", static_cast< cppu::OWeakObject * >(this), + 0); + } catch (css::registry::InvalidRegistryException & e) { + throw css::lang::IllegalArgumentException( + "InvalidRegistryException: " + e.Message, + static_cast< cppu::OWeakObject * >(this), 0); + } + } + insertExtraData(extra); +} + +void cppuhelper::ServiceManager::insertLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo) +{ + assert(factoryInfo.is()); + rtl::OUString name(factoryInfo->getImplementationName()); + css::uno::Reference< css::lang::XSingleComponentFactory > f1( + factoryInfo, css::uno::UNO_QUERY); + css::uno::Reference< css::lang::XSingleServiceFactory > f2; + if (!f1.is()) { + f2 = css::uno::Reference< css::lang::XSingleServiceFactory >( + factoryInfo, css::uno::UNO_QUERY); + } + css::uno::Reference< css::lang::XComponent > comp( + factoryInfo, css::uno::UNO_QUERY); + boost::shared_ptr< Data::Implementation > impl( + new Data::Implementation(name, f1, f2, comp)); + Data extra; + if (!name.isEmpty()) { + extra.namedImplementations.insert( + Data::NamedImplementations::value_type(name, impl)); + } + extra.dynamicImplementations.insert( + Data::DynamicImplementations::value_type(factoryInfo, impl)); + css::uno::Sequence< rtl::OUString > services( + factoryInfo->getSupportedServiceNames()); + for (sal_Int32 i = 0; i != services.getLength(); ++i) { + impl->info->services.push_back(services[i]); + extra.services[services[i]].push_back(impl); + } + if (insertExtraData(extra) && comp.is()) { + comp->addEventListener(this); + } +} + +bool cppuhelper::ServiceManager::insertExtraData(Data const & extra) { + { + osl::MutexGuard g(rBHelper.rMutex); + if (isDisposed()) { + return false; + } + for (Data::NamedImplementations::const_iterator i( + extra.namedImplementations.begin()); + i != extra.namedImplementations.end(); ++i) + { + if (data_.namedImplementations.find(i->first) + != data_.namedImplementations.end()) + { + throw css::lang::IllegalArgumentException( + "Insert duplicate implementation name " + i->first, + static_cast< cppu::OWeakObject * >(this), 0); + } + } + for (Data::DynamicImplementations::const_iterator i( + extra.dynamicImplementations.begin()); + i != extra.dynamicImplementations.end(); ++i) + { + if (data_.dynamicImplementations.find(i->first) + != data_.dynamicImplementations.end()) + { + throw css::lang::IllegalArgumentException( + "Insert duplicate factory object", + static_cast< cppu::OWeakObject * >(this), 0); + } + } + //TODO: The below leaves data_ in an inconsistent state upon exceptions: + data_.namedImplementations.insert( + extra.namedImplementations.begin(), + extra.namedImplementations.end()); + data_.dynamicImplementations.insert( + extra.dynamicImplementations.begin(), + extra.dynamicImplementations.end()); + insertImplementationMap(&data_.services, extra.services); + insertImplementationMap(&data_.singletons, extra.singletons); + } + //TODO: Updating the component context singleton data should be part of the + // atomic service manager update: + if (!extra.singletons.empty()) { + assert(context_.is()); + css::uno::Reference< css::container::XNameContainer > cont( + context_, css::uno::UNO_QUERY_THROW); + for (Data::ImplementationMap::const_iterator i( + extra.singletons.begin()); + i != extra.singletons.end(); ++i) + { + rtl::OUString name("/singletons/" + i->first); + //TODO: Update should be atomic: + try { + cont->removeByName(name + "/arguments"); + } catch (const css::container::NoSuchElementException &) {} + assert(!i->second.empty()); + assert(i->second[0].get() != 0); + SAL_INFO_IF( + i->second.size() > 1, "cppuhelper", + "Arbitrarily chosing " << i->second[0]->info->name + << " among multiple implementations for singleton " + << i->first); + try { + cont->insertByName( + name + "/service", css::uno::Any(i->second[0]->info->name)); + } catch (css::container::ElementExistException &) { + cont->replaceByName( + name + "/service", css::uno::Any(i->second[0]->info->name)); + } + try { + cont->insertByName(name, css::uno::Any()); + } catch (css::container::ElementExistException &) { + SAL_INFO("cppuhelper", "Overwriting singleton " << i->first); + cont->replaceByName(name, css::uno::Any()); + } + } + } + return true; +} + +void cppuhelper::ServiceManager::removeRdbFiles( + std::vector< rtl::OUString > const & uris) +{ + // The underlying data structures make this function somewhat inefficient, + // but the assumption is that it is rarely called (and that if it is called, + // it is called with a uris vector of size one): + std::vector< boost::shared_ptr< Data::Implementation > > clear; + { + osl::MutexGuard g(rBHelper.rMutex); + for (std::vector< rtl::OUString >::const_iterator i(uris.begin()); + i != uris.end(); ++i) + { + for (Data::NamedImplementations::iterator j( + data_.namedImplementations.begin()); + j != data_.namedImplementations.end();) + { + assert(j->second.get() != 0); + if (j->second->info->rdbFile == *i) { + clear.push_back(j->second); + //TODO: The below leaves data_ in an inconsistent state upon + // exceptions: + removeFromImplementationMap( + &data_.services, j->second->info->services, j->second); + removeFromImplementationMap( + &data_.singletons, j->second->info->singletons, + j->second); + data_.namedImplementations.erase(j++); + } else { + ++j; + } + } + } + } + //TODO: Update the component context singleton data +} + +bool cppuhelper::ServiceManager::removeLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo, + bool removeListener) +{ + assert(factoryInfo.is()); + boost::shared_ptr< Data::Implementation > clear; + css::uno::Reference< css::lang::XComponent > comp; + { + osl::MutexGuard g(rBHelper.rMutex); + Data::DynamicImplementations::iterator i( + data_.dynamicImplementations.find(factoryInfo)); + if (i == data_.dynamicImplementations.end()) { + return isDisposed(); + } + assert(i->second.get() != 0); + clear = i->second; + //TODO: The below leaves data_ in an inconsistent state upon exceptions: + removeFromImplementationMap( + &data_.services, i->second->info->services, i->second); + removeFromImplementationMap( + &data_.singletons, i->second->info->singletons, i->second); + if (!i->second->info->name.isEmpty()) { + data_.namedImplementations.erase(i->second->info->name); + } + data_.dynamicImplementations.erase(i); + if (removeListener) { + comp = i->second->component; + } + } + if (comp.is()) { + removeEventListenerFromComponent(comp); + } + return true; +} + +void cppuhelper::ServiceManager::removeImplementation(rtl::OUString name) { + // The underlying data structures make this function somewhat inefficient, + // but the assumption is that it is rarely called: + boost::shared_ptr< Data::Implementation > clear; + { + osl::MutexGuard g(rBHelper.rMutex); + if (isDisposed()) { + return; + } + Data::NamedImplementations::iterator i( + data_.namedImplementations.find(name)); + if (i == data_.namedImplementations.end()) { + throw css::container::NoSuchElementException( + "Remove non-inserted implementation " + name, + static_cast< cppu::OWeakObject * >(this)); + } + assert(i->second.get() != 0); + clear = i->second; + //TODO: The below leaves data_ in an inconsistent state upon exceptions: + removeFromImplementationMap( + &data_.services, i->second->info->services, i->second); + removeFromImplementationMap( + &data_.singletons, i->second->info->singletons, i->second); + for (Data::DynamicImplementations::iterator j( + data_.dynamicImplementations.begin()); + j != data_.dynamicImplementations.end(); ++j) + { + if (j->second == i->second) { + data_.dynamicImplementations.erase(j); + break; + } + } + data_.namedImplementations.erase(i); + } +} + +boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > +cppuhelper::ServiceManager::findServiceImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context, + rtl::OUString const & specifier) +{ + boost::shared_ptr< Data::Implementation > impl; + bool loaded; + { + osl::MutexGuard g(rBHelper.rMutex); + Data::ImplementationMap::const_iterator i( + data_.services.find(specifier)); + if (i == data_.services.end()) { + Data::NamedImplementations::const_iterator j( + data_.namedImplementations.find(specifier)); + if (j == data_.namedImplementations.end()) { + SAL_INFO("cppuhelper", "No implementation for " << specifier); + return boost::shared_ptr< Data::Implementation >(); + } + impl = j->second; + } else { + assert(!i->second.empty()); + SAL_INFO_IF( + i->second.size() > 1, "cppuhelper", + "Arbitrarily chosing " << i->second[0]->info->name + << " among multiple implementations for " << i->first); + impl = i->second[0]; + } + assert(impl.get() != 0); + loaded = impl->loaded; + } + //TODO: There is a race here, as the relevant service factory can be removed + // while the mutex is unlocked and loading can thus fail, as the entity from + // which to load can disappear once the service factory is removed. + if (!loaded) { + css::uno::Reference< css::lang::XSingleComponentFactory > f1; + css::uno::Reference< css::lang::XSingleServiceFactory > f2; + loadImplementation(context, impl->info, &f1, &f2); + osl::MutexGuard g(rBHelper.rMutex); + if (!(isDisposed() || impl->loaded)) { + impl->loaded = true; + impl->factory1 = f1; + impl->factory2 = f2; + } + } + return impl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/servicemanager.hxx b/cppuhelper/source/servicemanager.hxx new file mode 100644 index 000000000000..e4a9dfaa9055 --- /dev/null +++ b/cppuhelper/source/servicemanager.hxx @@ -0,0 +1,338 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CPPUHELPER_SOURCE_SERVICEMANAGER_HXX +#define INCLUDED_CPPUHELPER_SOURCE_SERVICEMANAGER_HXX + +#include "sal/config.h" + +#include +#include +#include + +#include "boost/noncopyable.hpp" +#include "boost/shared_ptr.hpp" +#include "com/sun/star/beans/XPropertySet.hpp" +#include "com/sun/star/beans/XPropertySetInfo.hpp" +#include "com/sun/star/container/XContentEnumerationAccess.hpp" +#include "com/sun/star/container/XSet.hpp" +#include "com/sun/star/lang/XEventListener.hpp" +#include "com/sun/star/lang/XMultiComponentFactory.hpp" +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/lang/XServiceInfo.hpp" +#include "com/sun/star/lang/XSingleServiceFactory.hpp" +#include "com/sun/star/uno/XComponentContext.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "cppuhelper/compbase8.hxx" +#include "osl/mutex.hxx" +#include "registry/registry.hxx" +#include "rtl/ustring.hxx" + +namespace cppuhelper { + +typedef cppu::WeakComponentImplHelper8< + css::lang::XServiceInfo, css::lang::XMultiServiceFactory, + css::lang::XMultiComponentFactory, css::container::XSet, + css::container::XContentEnumerationAccess, css::beans::XPropertySet, + css::beans::XPropertySetInfo, css::lang::XEventListener > +ServiceManagerBase; + +class ServiceManager: + private osl::Mutex, public ServiceManagerBase, private boost::noncopyable +{ +public: + struct Data: private boost::noncopyable { + struct ImplementationInfo: private boost::noncopyable { + ImplementationInfo( + rtl::OUString const & theName, rtl::OUString const & theLoader, + rtl::OUString const & theUri, rtl::OUString const & thePrefix, + css::uno::Reference< css::uno::XComponentContext > const & + theAlienContext, + rtl::OUString const & theRdbFile): + name(theName), loader(theLoader), uri(theUri), + prefix(thePrefix), alienContext(theAlienContext), + rdbFile(theRdbFile) + {} + + explicit ImplementationInfo(rtl::OUString const & theName): + name(theName) {} + + rtl::OUString const name; + rtl::OUString const loader; + rtl::OUString const uri; + rtl::OUString const prefix; + css::uno::Reference< css::uno::XComponentContext > const + alienContext; + rtl::OUString const rdbFile; + std::vector< rtl::OUString > services; + std::vector< rtl::OUString > singletons; + }; + + struct Implementation: private boost::noncopyable { + Implementation( + rtl::OUString const & name, rtl::OUString const & loader, + rtl::OUString const & uri, rtl::OUString const & prefix, + css::uno::Reference< css::uno::XComponentContext > const & + alienContext, + rtl::OUString const & rdbFile): + info( + new ImplementationInfo( + name, loader, uri, prefix, alienContext, rdbFile)), + loaded(false) + {} + + Implementation( + rtl::OUString const & name, + css::uno::Reference< css::lang::XSingleComponentFactory > + const & theFactory1, + css::uno::Reference< css::lang::XSingleServiceFactory > const & + theFactory2, + css::uno::Reference< css::lang::XComponent > const & + theComponent): + info(new ImplementationInfo(name)), factory1(theFactory1), + factory2(theFactory2), component(theComponent), loaded(true) + {} + + boost::shared_ptr< ImplementationInfo > info; + css::uno::Reference< css::lang::XSingleComponentFactory > factory1; + css::uno::Reference< css::lang::XSingleServiceFactory > factory2; + css::uno::Reference< css::lang::XComponent > component; + bool loaded; + }; + + typedef std::map< rtl::OUString, boost::shared_ptr< Implementation > > + NamedImplementations; + + typedef + std::map< + css::uno::Reference< css::lang::XServiceInfo >, + boost::shared_ptr< Implementation > > + DynamicImplementations; + + typedef + std::map< + rtl::OUString, + std::vector< boost::shared_ptr< Implementation > > > + ImplementationMap; + + NamedImplementations namedImplementations; + DynamicImplementations dynamicImplementations; + ImplementationMap services; + ImplementationMap singletons; + }; + + explicit ServiceManager(rtl::OUString const & rdbUris): + ServiceManagerBase(*static_cast< osl::Mutex * >(this)) + { readRdbs(rdbUris); } + + using ServiceManagerBase::acquire; + using ServiceManagerBase::release; + + void setContext( + css::uno::Reference< css::uno::XComponentContext > const & context) + { + assert(context.is()); + assert(!context_.is()); + context_ = context; + } + + css::uno::Reference< css::uno::XComponentContext > getContext() const { + assert(context_.is()); + return context_; + } + + Data const & getData() const { return data_; } + + void loadImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context, + boost::shared_ptr< Data::ImplementationInfo > const & info, + css::uno::Reference< css::lang::XSingleComponentFactory > * factory1, + css::uno::Reference< css::lang::XSingleServiceFactory > * factory2); + + virtual rtl::OUString SAL_CALL getImplementationName() + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) + throw (css::uno::RuntimeException); + + virtual css::uno::Sequence< rtl::OUString > SAL_CALL + getSupportedServiceNames() throw (css::uno::RuntimeException); + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( + rtl::OUString const & aServiceSpecifier) + throw (css::uno::Exception, css::uno::RuntimeException); + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArguments( + rtl::OUString const & ServiceSpecifier, + css::uno::Sequence< css::uno::Any > const & Arguments) + throw (css::uno::Exception, css::uno::RuntimeException); + + virtual css::uno::Sequence< rtl::OUString > SAL_CALL + getAvailableServiceNames() throw (css::uno::RuntimeException); + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithContext( + rtl::OUString const & aServiceSpecifier, + css::uno::Reference< css::uno::XComponentContext > const & Context) + throw (css::uno::Exception, css::uno::RuntimeException); + + virtual css::uno::Reference< css::uno::XInterface > SAL_CALL + createInstanceWithArgumentsAndContext( + rtl::OUString const & ServiceSpecifier, + css::uno::Sequence< css::uno::Any > const & Arguments, + css::uno::Reference< css::uno::XComponentContext > const & Context) + throw (css::uno::Exception, css::uno::RuntimeException); + + virtual css::uno::Type SAL_CALL getElementType() + throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL hasElements() throw (css::uno::RuntimeException); + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL + createEnumeration() throw (css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL has(css::uno::Any const & aElement) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL insert(css::uno::Any const & aElement) + throw ( + css::lang::IllegalArgumentException, + css::container::ElementExistException, css::uno::RuntimeException); + + virtual void SAL_CALL remove(css::uno::Any const & aElement) + throw ( + css::lang::IllegalArgumentException, + css::container::NoSuchElementException, css::uno::RuntimeException); + + virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL + createContentEnumeration(rtl::OUString const & aServiceName) + throw (css::uno::RuntimeException); + + virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL + getPropertySetInfo() throw (css::uno::RuntimeException); + + virtual void SAL_CALL setPropertyValue( + rtl::OUString const & aPropertyName, css::uno::Any const & aValue) + throw ( + css::beans::UnknownPropertyException, + css::beans::PropertyVetoException, + css::lang::IllegalArgumentException, + css::lang::WrappedTargetException, css::uno::RuntimeException); + + virtual css::uno::Any SAL_CALL getPropertyValue( + rtl::OUString const & PropertyName) + throw ( + css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, css::uno::RuntimeException); + + virtual void SAL_CALL addPropertyChangeListener( + rtl::OUString const & aPropertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & + xListener) + throw ( + css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, css::uno::RuntimeException); + + virtual void SAL_CALL removePropertyChangeListener( + rtl::OUString const & aPropertyName, + css::uno::Reference< css::beans::XPropertyChangeListener > const & + aListener) + throw ( + css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, css::uno::RuntimeException); + + virtual void SAL_CALL addVetoableChangeListener( + rtl::OUString const & PropertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & + aListener) + throw ( + css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, css::uno::RuntimeException); + + virtual void SAL_CALL removeVetoableChangeListener( + rtl::OUString const & PropertyName, + css::uno::Reference< css::beans::XVetoableChangeListener > const & + aListener) + throw ( + css::beans::UnknownPropertyException, + css::lang::WrappedTargetException, css::uno::RuntimeException); + + virtual css::uno::Sequence< css::beans::Property > SAL_CALL getProperties() + throw (css::uno::RuntimeException); + + virtual css::beans::Property SAL_CALL getPropertyByName( + rtl::OUString const & aName) + throw ( + css::beans::UnknownPropertyException, css::uno::RuntimeException); + + virtual sal_Bool SAL_CALL hasPropertyByName(rtl::OUString const & Name) + throw (css::uno::RuntimeException); + + virtual void SAL_CALL disposing(css::lang::EventObject const & Source) + throw (css::uno::RuntimeException); + +private: + virtual ~ServiceManager() {} + + virtual void SAL_CALL disposing(); + + // needs to be called with rBHelper.rMutex locked: + bool isDisposed() { return rBHelper.bDisposed || rBHelper.bInDispose; } + + void removeEventListenerFromComponent( + css::uno::Reference< css::lang::XComponent > const & component); + + void readRdbs(rtl::OUString const & uris); + + void readRdbDirectory(rtl::OUString const & uri, bool optional); + + void readRdbFile(rtl::OUString const & uri, bool optional); + + bool readLegacyRdbFile(rtl::OUString const & uri); + + rtl::OUString readLegacyRdbString( + rtl::OUString const & uri, RegistryKey & key, + rtl::OUString const & path); + + void readLegacyRdbStrings( + rtl::OUString const & uri, RegistryKey & key, + rtl::OUString const & path, std::vector< rtl::OUString > * strings); + + void insertRdbFiles( + std::vector< rtl::OUString > const & uris, + css::uno::Reference< css::uno::XComponentContext > const & + alientContext); + + void insertLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo); + + bool insertExtraData(Data const & extra); + + void removeRdbFiles(std::vector< rtl::OUString > const & uris); + + bool removeLegacyFactory( + css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo, + bool removeListener); + + void removeImplementation(rtl::OUString name); + + boost::shared_ptr< Data::Implementation > findServiceImplementation( + css::uno::Reference< css::uno::XComponentContext > const & context, + rtl::OUString const & specifier); + + css::uno::Reference< css::uno::XComponentContext > context_; + Data data_; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/typedescriptionprovider.cxx b/cppuhelper/source/typedescriptionprovider.cxx new file mode 100644 index 000000000000..62ff40e61749 --- /dev/null +++ b/cppuhelper/source/typedescriptionprovider.cxx @@ -0,0 +1,145 @@ +/* -*- 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/. + */ + +#include "sal/config.h" + +#include + +#include "com/sun/star/lang/XInitialization.hpp" +#include "com/sun/star/lang/XSingleServiceFactory.hpp" +#include "com/sun/star/registry/InvalidRegistryException.hpp" +#include "com/sun/star/registry/XSimpleRegistry.hpp" +#include "com/sun/star/uno/DeploymentException.hpp" +#include "com/sun/star/uno/Reference.hxx" +#include "cppuhelper/shlib.hxx" +#include "osl/file.hxx" +#include "rtl/ustring.hxx" + +#include "paths.hxx" +#include "servicefactory_detail.hxx" +#include "typedescriptionprovider.hxx" + +namespace { + +css::uno::Reference< css::registry::XSimpleRegistry > readTypeRdbFile( + rtl::OUString const & uri, bool optional, + css::uno::Reference< css::registry::XSimpleRegistry > const & lastRegistry, + css::uno::Reference< css::lang::XSingleServiceFactory > const & + simpleRegistryFactory, + css::uno::Reference< css::lang::XSingleServiceFactory > const & + nestedRegistryFactory) +{ + assert(simpleRegistryFactory.is() && nestedRegistryFactory.is()); + try { + css::uno::Reference< css::registry::XSimpleRegistry > simple( + simpleRegistryFactory->createInstance(), css::uno::UNO_QUERY_THROW); + simple->open(uri, true, false); + if (lastRegistry.is()) { + css::uno::Reference< css::registry::XSimpleRegistry > nested( + nestedRegistryFactory->createInstance(), + css::uno::UNO_QUERY_THROW); + css::uno::Sequence< css::uno::Any > args(2); + args[0] <<= lastRegistry; + args[1] <<= simple; + css::uno::Reference< css::lang::XInitialization >( + nested, css::uno::UNO_QUERY_THROW)-> + initialize(args); + return nested; + } else { + return simple; + } + } catch (css::registry::InvalidRegistryException & e) { + if (!optional) { + throw css::uno::DeploymentException( + "Invalid registry " + uri + ":" + e.Message, + css::uno::Reference< css::uno::XInterface >()); + } + SAL_INFO("cppuhelper", "Ignored optional " << uri); + return lastRegistry; + } +} + +css::uno::Reference< css::registry::XSimpleRegistry > readTypeRdbDirectory( + rtl::OUString const & uri, bool optional, + css::uno::Reference< css::registry::XSimpleRegistry > const & lastRegistry, + css::uno::Reference< css::lang::XSingleServiceFactory > const & + simpleRegistryFactory, + css::uno::Reference< css::lang::XSingleServiceFactory > const & + nestedRegistryFactory) +{ + assert(simpleRegistryFactory.is() && nestedRegistryFactory.is()); + osl::Directory dir(uri); + switch (dir.open()) { + case osl::FileBase::E_None: + break; + case osl::FileBase::E_NOENT: + if (optional) { + SAL_INFO("cppuhelper", "Ignored optional " << uri); + return lastRegistry; + } + // fall through + default: + throw css::uno::DeploymentException( + "Cannot open directory " + uri, + css::uno::Reference< css::uno::XInterface >()); + } + css::uno::Reference< css::registry::XSimpleRegistry > last(lastRegistry); + for (;;) { + rtl::OUString fileUri; + if (!cppu::nextDirectoryItem(dir, &fileUri)) { + break; + } + last = readTypeRdbFile( + fileUri, optional, last, simpleRegistryFactory, + nestedRegistryFactory); + } + return last; +} + +} + +css::uno::Reference< css::registry::XSimpleRegistry > +cppuhelper::createTypeRegistry( + rtl::OUString const & uris, rtl::OUString const & libraryDirectoryUri) +{ + css::uno::Reference< css::lang::XMultiComponentFactory > factory( + cppu::bootstrapInitialSF(libraryDirectoryUri)); + css::uno::Reference< css::lang::XSingleServiceFactory > simpleRegs( + cppu::loadSharedLibComponentFactory( + "bootstrap.uno" SAL_DLLEXTENSION, libraryDirectoryUri, + "com.sun.star.comp.stoc.SimpleRegistry", + css::uno::Reference< css::lang::XMultiServiceFactory >( + factory, css::uno::UNO_QUERY_THROW), + css::uno::Reference< css::registry::XRegistryKey >()), + css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::lang::XSingleServiceFactory > nestedRegs( + cppu::loadSharedLibComponentFactory( + "bootstrap.uno" SAL_DLLEXTENSION, libraryDirectoryUri, + "com.sun.star.comp.stoc.NestedRegistry", + css::uno::Reference< css::lang::XMultiServiceFactory >( + factory, css::uno::UNO_QUERY_THROW), + css::uno::Reference< css::registry::XRegistryKey >()), + css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::registry::XSimpleRegistry > reg; + for (sal_Int32 i = 0; i != -1;) { + rtl::OUString uri(uris.getToken(0, ' ', i)); + if (uri.isEmpty()) { + continue; + } + bool optional; + bool directory; + cppu::decodeRdbUri(&uri, &optional, &directory); + reg = directory + ? readTypeRdbDirectory(uri, optional, reg, simpleRegs, nestedRegs) + : readTypeRdbFile(uri, optional, reg, simpleRegs, nestedRegs); + } + return reg; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/cppuhelper/source/typedescriptionprovider.hxx b/cppuhelper/source/typedescriptionprovider.hxx new file mode 100644 index 000000000000..716f2adaee05 --- /dev/null +++ b/cppuhelper/source/typedescriptionprovider.hxx @@ -0,0 +1,31 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_CPPUHELPER_SOURCE_TYPEDESCRIPTIONPROVIDER_HXX +#define INCLUDED_CPPUHELPER_SOURCE_TYPEDESCRIPTIONPROVIDER_HXX + +#include "sal/config.h" + +#include "com/sun/star/uno/Reference.hxx" + +namespace com { namespace sun { namespace star { namespace uno { + class XSimpleRegistry; +} } } } +namespace rtl { class OUString; } + +namespace cppuhelper { + +css::uno::Reference< css::registry::XSimpleRegistry > createTypeRegistry( + rtl::OUString const & uris, rtl::OUString const & libraryDirectoryUri); + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit