1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <sal/config.h>
17 #include <com/sun/star/beans/NamedValue.hpp>
18 #include <com/sun/star/beans/PropertyAttribute.hpp>
19 #include <com/sun/star/container/ElementExistException.hpp>
20 #include <com/sun/star/container/XEnumeration.hpp>
21 #include <com/sun/star/container/XNameContainer.hpp>
22 #include <com/sun/star/lang/XInitialization.hpp>
23 #include <com/sun/star/lang/XServiceInfo.hpp>
24 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
25 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
26 #include <com/sun/star/loader/XImplementationLoader.hpp>
27 #include <com/sun/star/registry/InvalidRegistryException.hpp>
28 #include <com/sun/star/uno/DeploymentException.hpp>
29 #include <com/sun/star/uno/Reference.hxx>
30 #include <com/sun/star/uno/XComponentContext.hpp>
31 #include <comphelper/sequence.hxx>
32 #include <cppuhelper/bootstrap.hxx>
33 #include <cppuhelper/component_context.hxx>
34 #include <cppuhelper/implbase.hxx>
35 #include <cppuhelper/supportsservice.hxx>
36 #include <cppuhelper/factory.hxx>
37 #include <osl/file.hxx>
38 #include <osl/module.hxx>
39 #include <rtl/ref.hxx>
40 #include <rtl/uri.hxx>
41 #include <rtl/ustring.hxx>
42 #include <rtl/ustrbuf.hxx>
43 #include <sal/log.hxx>
44 #include <uno/environment.hxx>
45 #include <uno/mapping.hxx>
47 #include "loadsharedlibcomponentfactory.hxx"
49 #include <registry/registry.hxx>
50 #include <xmlreader/xmlreader.hxx>
53 #include "servicemanager.hxx"
57 void insertImplementationMap(
58 cppuhelper::ServiceManager::Data::ImplementationMap
* destination
,
59 cppuhelper::ServiceManager::Data::ImplementationMap
const & source
)
61 assert(destination
!= nullptr);
62 for (const auto& [rName
, rImpls
] : source
)
66 cppuhelper::ServiceManager::Data::Implementation
> > & impls
67 = (*destination
)[rName
];
68 impls
.insert(impls
.end(), rImpls
.begin(), rImpls
.end());
72 void removeFromImplementationMap(
73 cppuhelper::ServiceManager::Data::ImplementationMap
* map
,
74 std::vector
< OUString
> const & elements
,
75 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
76 const & implementation
)
78 // The underlying data structures make this function somewhat inefficient,
79 // but the assumption is that it is rarely called:
80 assert(map
!= nullptr);
81 for (const auto& rElement
: elements
)
83 cppuhelper::ServiceManager::Data::ImplementationMap::iterator
j(
85 assert(j
!= map
->end());
88 cppuhelper::ServiceManager::Data::Implementation
> >::iterator
89 k(std::find(j
->second
.begin(), j
->second
.end(), implementation
));
90 assert(k
!= j
->second
.end());
92 if (j
->second
.empty()) {
98 // For simplicity, this code keeps throwing
99 // css::registry::InvalidRegistryException for invalid XML rdbs (even though
100 // that does not fit the exception's name):
104 OUString
const & uri
,
105 css::uno::Reference
< css::uno::XComponentContext
> const & alienContext
,
106 cppuhelper::ServiceManager::Data
* data
);
108 Parser(const Parser
&) = delete;
109 const Parser
& operator=(const Parser
&) = delete;
112 void handleComponent();
114 void handleImplementation();
116 void handleService();
118 void handleSingleton();
120 OUString
getNameAttribute();
122 xmlreader::XmlReader reader_
;
123 css::uno::Reference
< css::uno::XComponentContext
> alienContext_
;
124 cppuhelper::ServiceManager::Data
* data_
;
125 OUString attrLoader_
;
127 OUString attrEnvironment_
;
128 OUString attrPrefix_
;
129 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
134 OUString
const & uri
,
135 css::uno::Reference
< css::uno::XComponentContext
> const & alienContext
,
136 cppuhelper::ServiceManager::Data
* data
):
137 reader_(uri
), alienContext_(alienContext
), data_(data
)
139 assert(data
!= nullptr);
140 int ucNsId
= reader_
.registerNamespaceIri(
142 RTL_CONSTASCII_STRINGPARAM(
143 "http://openoffice.org/2010/uno-components")));
145 STATE_BEGIN
, STATE_END
, STATE_COMPONENTS
, STATE_COMPONENT_INITIAL
,
146 STATE_COMPONENT
, STATE_IMPLEMENTATION
, STATE_SERVICE
, STATE_SINGLETON
};
147 for (State state
= STATE_BEGIN
;;) {
148 xmlreader::Span name
;
150 xmlreader::XmlReader::Result res
= reader_
.nextItem(
151 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
154 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
155 && name
.equals(RTL_CONSTASCII_STRINGPARAM("components")))
157 state
= STATE_COMPONENTS
;
160 throw css::registry::InvalidRegistryException(
161 reader_
.getUrl() + ": unexpected item in outer level");
163 if (res
== xmlreader::XmlReader::Result::Done
) {
166 throw css::registry::InvalidRegistryException(
167 reader_
.getUrl() + ": unexpected item in outer level");
168 case STATE_COMPONENTS
:
169 if (res
== xmlreader::XmlReader::Result::End
) {
173 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
174 && name
.equals(RTL_CONSTASCII_STRINGPARAM("component")))
177 state
= STATE_COMPONENT_INITIAL
;
180 throw css::registry::InvalidRegistryException(
181 reader_
.getUrl() + ": unexpected item in <components>");
182 case STATE_COMPONENT
:
183 if (res
== xmlreader::XmlReader::Result::End
) {
184 state
= STATE_COMPONENTS
;
188 case STATE_COMPONENT_INITIAL
:
189 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
190 && name
.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
192 handleImplementation();
193 state
= STATE_IMPLEMENTATION
;
196 throw css::registry::InvalidRegistryException(
197 reader_
.getUrl() + ": unexpected item in <component>");
198 case STATE_IMPLEMENTATION
:
199 if (res
== xmlreader::XmlReader::Result::End
) {
200 state
= STATE_COMPONENT
;
203 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
204 && name
.equals(RTL_CONSTASCII_STRINGPARAM("service")))
207 state
= STATE_SERVICE
;
210 if (res
== xmlreader::XmlReader::Result::Begin
&& nsId
== ucNsId
211 && name
.equals(RTL_CONSTASCII_STRINGPARAM("singleton")))
214 state
= STATE_SINGLETON
;
217 throw css::registry::InvalidRegistryException(
218 reader_
.getUrl() + ": unexpected item in <implementation>");
220 if (res
== xmlreader::XmlReader::Result::End
) {
221 state
= STATE_IMPLEMENTATION
;
224 throw css::registry::InvalidRegistryException(
225 reader_
.getUrl() + ": unexpected item in <service>");
226 case STATE_SINGLETON
:
227 if (res
== xmlreader::XmlReader::Result::End
) {
228 state
= STATE_IMPLEMENTATION
;
231 throw css::registry::InvalidRegistryException(
232 reader_
.getUrl() + ": unexpected item in <service>");
237 void Parser::handleComponent() {
238 attrLoader_
= OUString();
239 attrUri_
= OUString();
240 attrEnvironment_
= OUString();
241 attrPrefix_
= OUString();
242 xmlreader::Span name
;
244 while (reader_
.nextAttribute(&nsId
, &name
)) {
245 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
246 && name
.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
248 if (!attrLoader_
.isEmpty()) {
249 throw css::registry::InvalidRegistryException(
251 + ": <component> has multiple \"loader\" attributes");
253 attrLoader_
= reader_
.getAttributeValue(false).convertFromUtf8();
254 if (attrLoader_
.isEmpty()) {
255 throw css::registry::InvalidRegistryException(
257 + ": <component> has empty \"loader\" attribute");
259 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
260 && name
.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
262 if (!attrUri_
.isEmpty()) {
263 throw css::registry::InvalidRegistryException(
265 + ": <component> has multiple \"uri\" attributes");
267 attrUri_
= reader_
.getAttributeValue(false).convertFromUtf8();
268 if (attrUri_
.isEmpty()) {
269 throw css::registry::InvalidRegistryException(
271 + ": <component> has empty \"uri\" attribute");
273 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
274 && name
.equals(RTL_CONSTASCII_STRINGPARAM("environment")))
276 if (!attrEnvironment_
.isEmpty()) {
277 throw css::registry::InvalidRegistryException(
279 ": <component> has multiple \"environment\" attributes");
281 attrEnvironment_
= reader_
.getAttributeValue(false)
283 if (attrEnvironment_
.isEmpty()) {
284 throw css::registry::InvalidRegistryException(
286 ": <component> has empty \"environment\" attribute");
288 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
289 && name
.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
291 if (!attrPrefix_
.isEmpty()) {
292 throw css::registry::InvalidRegistryException(
294 ": <component> has multiple \"prefix\" attributes");
296 attrPrefix_
= reader_
.getAttributeValue(false).convertFromUtf8();
297 if (attrPrefix_
.isEmpty()) {
298 throw css::registry::InvalidRegistryException(
300 ": <component> has empty \"prefix\" attribute");
303 throw css::registry::InvalidRegistryException(
304 reader_
.getUrl() + ": unexpected attribute \""
305 + name
.convertFromUtf8() + "\" in <component>");
308 if (attrLoader_
.isEmpty()) {
309 throw css::registry::InvalidRegistryException(
310 reader_
.getUrl() + ": <component> is missing \"loader\" attribute");
312 if (attrUri_
.isEmpty()) {
313 throw css::registry::InvalidRegistryException(
314 reader_
.getUrl() + ": <component> is missing \"uri\" attribute");
316 #ifndef DISABLE_DYNLOADING
318 attrUri_
= rtl::Uri::convertRelToAbs(reader_
.getUrl(), attrUri_
);
319 } catch (const rtl::MalformedUriException
& e
) {
320 throw css::registry::InvalidRegistryException(
321 reader_
.getUrl() + ": bad \"uri\" attribute: " + e
.getMessage());
326 void Parser::handleImplementation() {
328 OUString attrConstructor
;
329 xmlreader::Span name
;
331 while (reader_
.nextAttribute(&nsId
, &name
)) {
332 if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
333 && name
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
335 if (!attrName
.isEmpty()) {
336 throw css::registry::InvalidRegistryException(
338 + ": <implementation> has multiple \"name\" attributes");
340 attrName
= reader_
.getAttributeValue(false).convertFromUtf8();
341 if (attrName
.isEmpty()) {
342 throw css::registry::InvalidRegistryException(
344 + ": <implementation> has empty \"name\" attribute");
346 } else if (nsId
== xmlreader::XmlReader::NAMESPACE_NONE
347 && name
.equals(RTL_CONSTASCII_STRINGPARAM("constructor")))
349 if (!attrConstructor
.isEmpty()) {
350 throw css::registry::InvalidRegistryException(
352 + ": <implementation> has multiple \"constructor\""
355 attrConstructor
= reader_
.getAttributeValue(false)
357 if (attrConstructor
.isEmpty()) {
358 throw css::registry::InvalidRegistryException(
360 + ": element has empty \"constructor\" attribute");
362 if (attrEnvironment_
.isEmpty()) {
363 throw css::registry::InvalidRegistryException(
365 + ": <implementation> has \"constructor\" attribute but"
366 " <component> has no \"environment\" attribute");
369 throw css::registry::InvalidRegistryException(
370 reader_
.getUrl() + ": unexpected element attribute \""
371 + name
.convertFromUtf8() + "\" in <implementation>");
374 if (attrName
.isEmpty()) {
375 throw css::registry::InvalidRegistryException(
377 + ": <implementation> is missing \"name\" attribute");
379 implementation_
.reset(
380 new cppuhelper::ServiceManager::Data::Implementation(
381 attrName
, attrLoader_
, attrUri_
, attrEnvironment_
, attrConstructor
,
382 attrPrefix_
, alienContext_
, reader_
.getUrl()));
383 if (!data_
->namedImplementations
.emplace(attrName
, implementation_
).
386 throw css::registry::InvalidRegistryException(
387 reader_
.getUrl() + ": duplicate <implementation name=\"" + attrName
392 void Parser::handleService() {
393 OUString
name(getNameAttribute());
394 implementation_
->info
->services
.push_back(name
);
395 data_
->services
[name
].push_back(implementation_
);
398 void Parser::handleSingleton() {
399 OUString
name(getNameAttribute());
400 implementation_
->info
->singletons
.push_back(name
);
401 data_
->singletons
[name
].push_back(implementation_
);
404 OUString
Parser::getNameAttribute() {
406 xmlreader::Span name
;
408 while (reader_
.nextAttribute(&nsId
, &name
)) {
409 if (nsId
!= xmlreader::XmlReader::NAMESPACE_NONE
410 || !name
.equals(RTL_CONSTASCII_STRINGPARAM("name")))
412 throw css::registry::InvalidRegistryException(
413 reader_
.getUrl() + ": expected element attribute \"name\"");
415 if (!attrName
.isEmpty()) {
416 throw css::registry::InvalidRegistryException(
418 + ": element has multiple \"name\" attributes");
420 attrName
= reader_
.getAttributeValue(false).convertFromUtf8();
421 if (attrName
.isEmpty()) {
422 throw css::registry::InvalidRegistryException(
423 reader_
.getUrl() + ": element has empty \"name\" attribute");
426 if (attrName
.isEmpty()) {
427 throw css::registry::InvalidRegistryException(
428 reader_
.getUrl() + ": element is missing \"name\" attribute");
433 class ContentEnumeration
:
434 public cppu::WeakImplHelper
< css::container::XEnumeration
>
437 explicit ContentEnumeration(std::vector
< css::uno::Any
> const & factories
):
438 factories_(factories
), iterator_(factories_
.begin()) {}
440 ContentEnumeration(const ContentEnumeration
&) = delete;
441 const ContentEnumeration
& operator=(const ContentEnumeration
&) = delete;
444 virtual ~ContentEnumeration() override
{}
446 virtual sal_Bool SAL_CALL
hasMoreElements() override
;
448 virtual css::uno::Any SAL_CALL
nextElement() override
;
451 std::vector
< css::uno::Any
> factories_
;
452 std::vector
< css::uno::Any
>::const_iterator iterator_
;
455 sal_Bool
ContentEnumeration::hasMoreElements()
457 osl::MutexGuard
g(mutex_
);
458 return iterator_
!= factories_
.end();
461 css::uno::Any
ContentEnumeration::nextElement()
463 osl::MutexGuard
g(mutex_
);
464 if (iterator_
== factories_
.end()) {
465 throw css::container::NoSuchElementException(
466 "Bootstrap service manager service enumerator has no more elements",
467 static_cast< cppu::OWeakObject
* >(this));
472 css::beans::Property
getDefaultContextProperty() {
473 return css::beans::Property(
474 "DefaultContext", -1,
475 cppu::UnoType
< css::uno::XComponentContext
>::get(),
476 css::beans::PropertyAttribute::READONLY
);
479 class SingletonFactory
:
480 public cppu::WeakImplHelper
<css::lang::XSingleComponentFactory
>
484 rtl::Reference
< cppuhelper::ServiceManager
> const & manager
,
486 cppuhelper::ServiceManager::Data::Implementation
> const &
488 manager_(manager
), implementation_(implementation
)
489 { assert(manager
.is()); assert(implementation
.get() != nullptr); }
491 SingletonFactory(const SingletonFactory
&) = delete;
492 const SingletonFactory
& operator=(const SingletonFactory
&) = delete;
495 virtual ~SingletonFactory() override
{}
497 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
498 createInstanceWithContext(
499 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
501 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
502 createInstanceWithArgumentsAndContext(
503 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
504 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
506 rtl::Reference
< cppuhelper::ServiceManager
> manager_
;
507 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
511 css::uno::Reference
< css::uno::XInterface
>
512 SingletonFactory::createInstanceWithContext(
513 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
515 manager_
->loadImplementation(Context
, implementation_
);
516 return implementation_
->createInstance(Context
, true);
519 css::uno::Reference
< css::uno::XInterface
>
520 SingletonFactory::createInstanceWithArgumentsAndContext(
521 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
522 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
524 manager_
->loadImplementation(Context
, implementation_
);
525 return implementation_
->createInstanceWithArguments(
526 Context
, true, Arguments
);
529 class ImplementationWrapper
:
530 public cppu::WeakImplHelper
<
531 css::lang::XSingleComponentFactory
, css::lang::XSingleServiceFactory
,
532 css::lang::XServiceInfo
>
535 ImplementationWrapper(
536 rtl::Reference
< cppuhelper::ServiceManager
> const & manager
,
538 cppuhelper::ServiceManager::Data::Implementation
> const &
540 manager_(manager
), implementation_(implementation
)
541 { assert(manager
.is()); assert(implementation
.get() != nullptr); }
543 ImplementationWrapper(const ImplementationWrapper
&) = delete;
544 const ImplementationWrapper
& operator=(const ImplementationWrapper
&) = delete;
547 virtual ~ImplementationWrapper() override
{}
549 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
550 createInstanceWithContext(
551 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
553 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
554 createInstanceWithArgumentsAndContext(
555 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
556 css::uno::Reference
< css::uno::XComponentContext
> const & Context
) override
;
558 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
559 createInstance() override
;
561 virtual css::uno::Reference
< css::uno::XInterface
> SAL_CALL
562 createInstanceWithArguments(
563 css::uno::Sequence
< css::uno::Any
> const & Arguments
) override
;
565 virtual OUString SAL_CALL
getImplementationName() override
;
567 virtual sal_Bool SAL_CALL
supportsService(OUString
const & ServiceName
) override
;
569 virtual css::uno::Sequence
< OUString
> SAL_CALL
570 getSupportedServiceNames() override
;
572 rtl::Reference
< cppuhelper::ServiceManager
> manager_
;
573 std::weak_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
577 css::uno::Reference
< css::uno::XInterface
>
578 ImplementationWrapper::createInstanceWithContext(
579 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
581 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
583 manager_
->loadImplementation(Context
, impl
);
584 return impl
->createInstance(Context
, false);
587 css::uno::Reference
< css::uno::XInterface
>
588 ImplementationWrapper::createInstanceWithArgumentsAndContext(
589 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
590 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
592 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
594 manager_
->loadImplementation(Context
, impl
);
595 return impl
->createInstanceWithArguments(
596 Context
, false, Arguments
);
599 css::uno::Reference
< css::uno::XInterface
>
600 ImplementationWrapper::createInstance()
602 return createInstanceWithContext(manager_
->getContext());
605 css::uno::Reference
< css::uno::XInterface
>
606 ImplementationWrapper::createInstanceWithArguments(
607 css::uno::Sequence
< css::uno::Any
> const & Arguments
)
609 return createInstanceWithArgumentsAndContext(
610 Arguments
, manager_
->getContext());
613 OUString
ImplementationWrapper::getImplementationName()
615 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
617 return impl
->info
->name
;
620 sal_Bool
ImplementationWrapper::supportsService(OUString
const & ServiceName
)
622 return cppu::supportsService(this, ServiceName
);
625 css::uno::Sequence
< OUString
>
626 ImplementationWrapper::getSupportedServiceNames()
628 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
> impl
= implementation_
.lock();
630 if (impl
->info
->services
.size()
631 > static_cast< sal_uInt32
>(SAL_MAX_INT32
))
633 throw css::uno::RuntimeException(
634 ("Implementation " + impl
->info
->name
635 + " supports too many services"),
636 static_cast< cppu::OWeakObject
* >(this));
638 return comphelper::containerToSequence(impl
->info
->services
);
643 css::uno::Reference
<css::uno::XInterface
>
644 cppuhelper::ServiceManager::Data::Implementation::createInstance(
645 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
646 bool singletonRequest
)
648 css::uno::Reference
<css::uno::XInterface
> inst
;
651 constructor(context
.get(), css::uno::Sequence
<css::uno::Any
>()),
653 } else if (factory1
.is()) {
654 inst
= factory1
->createInstanceWithContext(context
);
656 assert(factory2
.is());
657 inst
= factory2
->createInstance();
659 updateDisposeSingleton(singletonRequest
, inst
);
663 css::uno::Reference
<css::uno::XInterface
>
664 cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments(
665 css::uno::Reference
<css::uno::XComponentContext
> const & context
,
666 bool singletonRequest
, css::uno::Sequence
<css::uno::Any
> const & arguments
)
668 css::uno::Reference
<css::uno::XInterface
> inst
;
670 inst
.set(constructor(context
.get(), arguments
), SAL_NO_ACQUIRE
);
671 //HACK: The constructor will either observe arguments and return inst
672 // that does not implement XInitialization (or null), or ignore
673 // arguments and return inst that implements XInitialization; this
674 // should be removed again once XInitialization-based implementations
676 css::uno::Reference
<css::lang::XInitialization
> init(
677 inst
, css::uno::UNO_QUERY
);
679 init
->initialize(arguments
);
681 } else if (factory1
.is()) {
682 inst
= factory1
->createInstanceWithArgumentsAndContext(
685 assert(factory2
.is());
686 inst
= factory2
->createInstanceWithArguments(arguments
);
688 updateDisposeSingleton(singletonRequest
, inst
);
692 void cppuhelper::ServiceManager::Data::Implementation::updateDisposeSingleton(
693 bool singletonRequest
,
694 css::uno::Reference
<css::uno::XInterface
> const & instance
)
696 // This is an optimization, to only call dispose once (from the component
697 // context) on a singleton that is obtained both via the component context
698 // and via the service manager; however, there is a harmless race here that
699 // may cause two calls to dispose nevertheless (also, this calls dispose on
700 // at most one of the instances obtained via the service manager, in case
701 // the implementation hands out different instances):
702 if (singletonRequest
) {
703 osl::MutexGuard
g(mutex
);
704 disposeSingleton
.clear();
706 } else if (!info
->singletons
.empty()) {
707 css::uno::Reference
<css::lang::XComponent
> comp(
708 instance
, css::uno::UNO_QUERY
);
710 osl::MutexGuard
g(mutex
);
712 disposeSingleton
= comp
;
718 void cppuhelper::ServiceManager::addSingletonContextEntries(
719 std::vector
< cppu::ContextEntry_Init
> * entries
)
721 assert(entries
!= nullptr);
722 for (const auto& [rName
, rImpls
] : data_
.singletons
)
724 assert(!rImpls
.empty());
725 assert(rImpls
[0].get() != nullptr);
727 rImpls
.size() > 1, "cppuhelper",
728 "Arbitrarily choosing " << rImpls
[0]->info
->name
729 << " among multiple implementations for " << rName
);
731 cppu::ContextEntry_Init(
732 "/singletons/" + rName
,
734 css::uno::Reference
<css::lang::XSingleComponentFactory
> >(
735 new SingletonFactory(this, rImpls
[0])),
740 void cppuhelper::ServiceManager::loadImplementation(
741 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
742 std::shared_ptr
< Data::Implementation
> const & implementation
)
744 assert(implementation
.get() != nullptr);
746 osl::MutexGuard
g(rBHelper
.rMutex
);
747 if (implementation
->status
== Data::Implementation::STATUS_LOADED
) {
753 uri
= cppu::bootstrap_expandUri(implementation
->info
->uri
);
754 } catch (css::lang::IllegalArgumentException
& e
) {
755 throw css::uno::DeploymentException(
756 "Cannot expand URI" + implementation
->info
->uri
+ ": " + e
.Message
,
757 static_cast< cppu::OWeakObject
* >(this));
759 cppuhelper::WrapperConstructorFn ctor
;
760 css::uno::Reference
< css::uno::XInterface
> f0
;
761 // Special handling of SharedLibrary loader, with support for environment,
762 // constructor, and prefix arguments:
763 if (!implementation
->info
->alienContext
.is()
764 && implementation
->info
->loader
== "com.sun.star.loader.SharedLibrary")
766 cppuhelper::detail::loadSharedLibComponentFactory(
767 uri
, implementation
->info
->environment
,
768 implementation
->info
->prefix
, implementation
->info
->name
,
769 implementation
->info
->constructor
, this, &ctor
, &f0
);
771 assert(!implementation
->info
->environment
.isEmpty());
775 !implementation
->info
->environment
.isEmpty(), "cppuhelper",
776 "Loader " << implementation
->info
->loader
777 << " and non-empty environment "
778 << implementation
->info
->environment
);
780 !implementation
->info
->prefix
.isEmpty(), "cppuhelper",
781 "Loader " << implementation
->info
->loader
782 << " and non-empty constructor "
783 << implementation
->info
->constructor
);
785 !implementation
->info
->prefix
.isEmpty(), "cppuhelper",
786 "Loader " << implementation
->info
->loader
787 << " and non-empty prefix " << implementation
->info
->prefix
);
788 css::uno::Reference
< css::uno::XComponentContext
> ctxt
;
789 css::uno::Reference
< css::lang::XMultiComponentFactory
> smgr
;
790 if (implementation
->info
->alienContext
.is()) {
791 ctxt
= implementation
->info
->alienContext
;
792 smgr
.set(ctxt
->getServiceManager(), css::uno::UNO_SET_THROW
);
794 assert(context
.is());
798 css::uno::Reference
< css::loader::XImplementationLoader
> loader(
799 smgr
->createInstanceWithContext(implementation
->info
->loader
, ctxt
),
800 css::uno::UNO_QUERY_THROW
);
801 f0
= loader
->activate(
802 implementation
->info
->name
, OUString(), uri
,
803 css::uno::Reference
< css::registry::XRegistryKey
>());
805 css::uno::Reference
<css::lang::XSingleComponentFactory
> f1
;
806 css::uno::Reference
<css::lang::XSingleServiceFactory
> f2
;
808 f1
.set(f0
, css::uno::UNO_QUERY
);
810 f2
.set(f0
, css::uno::UNO_QUERY
);
812 throw css::uno::DeploymentException(
813 ("Implementation " + implementation
->info
->name
814 + " does not provide a constructor or factory"),
815 static_cast< cppu::OWeakObject
* >(this));
819 //TODO: There is a race here, as the relevant service factory can be removed
820 // while the mutex is unlocked and loading can thus fail, as the entity from
821 // which to load can disappear once the service factory is removed.
822 osl::MutexGuard
g(rBHelper
.rMutex
);
824 || implementation
->status
== Data::Implementation::STATUS_LOADED
))
826 implementation
->status
= Data::Implementation::STATUS_LOADED
;
827 implementation
->constructor
= ctor
;
828 implementation
->factory1
= f1
;
829 implementation
->factory2
= f2
;
833 void cppuhelper::ServiceManager::disposing() {
834 std::vector
< css::uno::Reference
<css::lang::XComponent
> > sngls
;
835 std::vector
< css::uno::Reference
< css::lang::XComponent
> > comps
;
838 osl::MutexGuard
g(rBHelper
.rMutex
);
839 for (const auto& rEntry
: data_
.namedImplementations
)
841 assert(rEntry
.second
.get() != nullptr);
842 if (!rEntry
.second
->info
->singletons
.empty()) {
843 osl::MutexGuard
g2(rEntry
.second
->mutex
);
844 if (rEntry
.second
->disposeSingleton
.is()) {
845 sngls
.push_back(rEntry
.second
->disposeSingleton
);
849 for (const auto& rEntry
: data_
.dynamicImplementations
)
851 assert(rEntry
.second
.get() != nullptr);
852 if (!rEntry
.second
->info
->singletons
.empty()) {
853 osl::MutexGuard
g2(rEntry
.second
->mutex
);
854 if (rEntry
.second
->disposeSingleton
.is()) {
855 sngls
.push_back(rEntry
.second
->disposeSingleton
);
858 if (rEntry
.second
->component
.is()) {
859 comps
.push_back(rEntry
.second
->component
);
862 data_
.namedImplementations
.swap(clear
.namedImplementations
);
863 data_
.dynamicImplementations
.swap(clear
.dynamicImplementations
);
864 data_
.services
.swap(clear
.services
);
865 data_
.singletons
.swap(clear
.singletons
);
867 for (const auto& rxSngl
: sngls
)
871 } catch (css::uno::RuntimeException
& e
) {
872 SAL_WARN("cppuhelper", "Ignoring " << e
<< " while disposing singleton");
875 for (const auto& rxComp
: comps
)
877 removeEventListenerFromComponent(rxComp
);
881 void cppuhelper::ServiceManager::initialize(
882 css::uno::Sequence
<css::uno::Any
> const & aArguments
)
885 if (aArguments
.getLength() != 1 || !(aArguments
[0] >>= arg
)
888 throw css::lang::IllegalArgumentException(
889 "invalid ServiceManager::initialize argument",
890 css::uno::Reference
<css::uno::XInterface
>(), 0);
892 preloadImplementations();
895 OUString
cppuhelper::ServiceManager::getImplementationName()
898 "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager";
901 sal_Bool
cppuhelper::ServiceManager::supportsService(
902 OUString
const & ServiceName
)
904 return cppu::supportsService(this, ServiceName
);
907 css::uno::Sequence
< OUString
>
908 cppuhelper::ServiceManager::getSupportedServiceNames()
910 return { "com.sun.star.lang.MultiServiceFactory", "com.sun.star.lang.ServiceManager" };
913 css::uno::Reference
< css::uno::XInterface
>
914 cppuhelper::ServiceManager::createInstance(
915 OUString
const & aServiceSpecifier
)
917 assert(context_
.is());
918 return createInstanceWithContext(aServiceSpecifier
, context_
);
921 css::uno::Reference
< css::uno::XInterface
>
922 cppuhelper::ServiceManager::createInstanceWithArguments(
923 OUString
const & ServiceSpecifier
,
924 css::uno::Sequence
< css::uno::Any
> const & Arguments
)
926 assert(context_
.is());
927 return createInstanceWithArgumentsAndContext(
928 ServiceSpecifier
, Arguments
, context_
);
931 css::uno::Sequence
< OUString
>
932 cppuhelper::ServiceManager::getAvailableServiceNames()
934 osl::MutexGuard
g(rBHelper
.rMutex
);
936 return css::uno::Sequence
< OUString
>();
938 if (data_
.services
.size() > static_cast< sal_uInt32
>(SAL_MAX_INT32
)) {
939 throw css::uno::RuntimeException(
940 "getAvailableServiceNames: too many services",
941 static_cast< cppu::OWeakObject
* >(this));
943 return comphelper::mapKeysToSequence(data_
.services
);
946 css::uno::Reference
< css::uno::XInterface
>
947 cppuhelper::ServiceManager::createInstanceWithContext(
948 OUString
const & aServiceSpecifier
,
949 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
951 std::shared_ptr
< Data::Implementation
> impl(
952 findServiceImplementation(Context
, aServiceSpecifier
));
953 return impl
== nullptr ? css::uno::Reference
<css::uno::XInterface
>()
954 : impl
->createInstance(Context
, false);
957 css::uno::Reference
< css::uno::XInterface
>
958 cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext(
959 OUString
const & ServiceSpecifier
,
960 css::uno::Sequence
< css::uno::Any
> const & Arguments
,
961 css::uno::Reference
< css::uno::XComponentContext
> const & Context
)
963 std::shared_ptr
< Data::Implementation
> impl(
964 findServiceImplementation(Context
, ServiceSpecifier
));
965 return impl
== nullptr ? css::uno::Reference
<css::uno::XInterface
>()
966 : impl
->createInstanceWithArguments(Context
, false, Arguments
);
969 css::uno::Type
cppuhelper::ServiceManager::getElementType()
971 return css::uno::Type();
974 sal_Bool
cppuhelper::ServiceManager::hasElements()
976 osl::MutexGuard
g(rBHelper
.rMutex
);
978 !(data_
.namedImplementations
.empty()
979 && data_
.dynamicImplementations
.empty());
982 css::uno::Reference
< css::container::XEnumeration
>
983 cppuhelper::ServiceManager::createEnumeration()
985 throw css::uno::RuntimeException(
986 "ServiceManager createEnumeration: method not supported",
987 static_cast< cppu::OWeakObject
* >(this));
990 sal_Bool
cppuhelper::ServiceManager::has(css::uno::Any
const &)
992 throw css::uno::RuntimeException(
993 "ServiceManager has: method not supported",
994 static_cast< cppu::OWeakObject
* >(this));
997 void cppuhelper::ServiceManager::insert(css::uno::Any
const & aElement
)
999 css::uno::Sequence
< css::beans::NamedValue
> args
;
1000 if (aElement
>>= args
) {
1001 std::vector
< OUString
> uris
;
1002 css::uno::Reference
< css::uno::XComponentContext
> alienContext
;
1003 for (sal_Int32 i
= 0; i
< args
.getLength(); ++i
) {
1004 if (args
[i
].Name
== "uri") {
1006 if (!(args
[i
].Value
>>= uri
)) {
1007 throw css::lang::IllegalArgumentException(
1009 static_cast< cppu::OWeakObject
* >(this), 0);
1011 uris
.push_back(uri
);
1012 } else if (args
[i
].Name
== "component-context") {
1013 if (alienContext
.is()) {
1014 throw css::lang::IllegalArgumentException(
1015 "Multiple component-context arguments",
1016 static_cast< cppu::OWeakObject
* >(this), 0);
1018 if (!(args
[i
].Value
>>= alienContext
) || !alienContext
.is()) {
1019 throw css::lang::IllegalArgumentException(
1020 "Bad component-context argument",
1021 static_cast< cppu::OWeakObject
* >(this), 0);
1024 throw css::lang::IllegalArgumentException(
1025 "Bad argument " + args
[i
].Name
,
1026 static_cast< cppu::OWeakObject
* >(this), 0);
1029 insertRdbFiles(uris
, alienContext
);
1032 css::uno::Reference
< css::lang::XServiceInfo
> info
;
1033 if ((aElement
>>= info
) && info
.is()) {
1034 insertLegacyFactory(info
);
1037 // At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in
1038 // module languagetool) contain an (actively registered) factory that does not
1039 // implement XServiceInfo (see <http://sourceforge.net/tracker/?
1040 // func=detail&aid=3526635&group_id=110216&atid=655717> "SingletonFactory should
1041 // implement XServiceInfo"); the old OServiceManager::insert
1042 // (stoc/source/servicemanager/servicemanager.cxx) silently did not add such
1043 // broken factories to its m_ImplementationNameMap, so ignore them here for
1044 // backwards compatibility of live-insertion of extensions, too.
1046 // (The plan was that this warning would go away (and we would do the
1047 // throw instead) for the incompatible LO 4, but we changed our mind):
1048 css::uno::Reference
< css::lang::XSingleComponentFactory
> legacy
;
1049 if ((aElement
>>= legacy
) && legacy
.is()) {
1052 "Ignored XSingleComponentFactory not implementing XServiceInfo");
1056 throw css::lang::IllegalArgumentException(
1057 "Bad insert element", static_cast< cppu::OWeakObject
* >(this), 0);
1060 void cppuhelper::ServiceManager::remove(css::uno::Any
const & aElement
)
1062 css::uno::Sequence
< css::beans::NamedValue
> args
;
1063 if (aElement
>>= args
) {
1064 std::vector
< OUString
> uris
;
1065 for (sal_Int32 i
= 0; i
< args
.getLength(); ++i
) {
1066 if (args
[i
].Name
!= "uri") {
1067 throw css::lang::IllegalArgumentException(
1068 "Bad argument " + args
[i
].Name
,
1069 static_cast< cppu::OWeakObject
* >(this), 0);
1072 if (!(args
[i
].Value
>>= uri
)) {
1073 throw css::lang::IllegalArgumentException(
1075 static_cast< cppu::OWeakObject
* >(this), 0);
1077 uris
.push_back(uri
);
1079 removeRdbFiles(uris
);
1082 css::uno::Reference
< css::lang::XServiceInfo
> info
;
1083 if ((aElement
>>= info
) && info
.is()) {
1084 if (!removeLegacyFactory(info
, true)) {
1085 throw css::container::NoSuchElementException(
1086 "Remove non-inserted factory object",
1087 static_cast< cppu::OWeakObject
* >(this));
1092 if (aElement
>>= impl
) {
1093 // For live-removal of extensions:
1094 removeImplementation(impl
);
1097 throw css::lang::IllegalArgumentException(
1098 "Bad remove element", static_cast< cppu::OWeakObject
* >(this), 0);
1101 css::uno::Reference
< css::container::XEnumeration
>
1102 cppuhelper::ServiceManager::createContentEnumeration(
1103 OUString
const & aServiceName
)
1105 std::vector
< std::shared_ptr
< Data::Implementation
> > impls
;
1107 osl::MutexGuard
g(rBHelper
.rMutex
);
1108 Data::ImplementationMap::const_iterator
i(
1109 data_
.services
.find(aServiceName
));
1110 if (i
!= data_
.services
.end()) {
1114 std::vector
< css::uno::Any
> factories
;
1115 for (const auto& rxImpl
: impls
)
1117 Data::Implementation
* impl
= rxImpl
.get();
1118 assert(impl
!= nullptr);
1120 osl::MutexGuard
g(rBHelper
.rMutex
);
1125 if (impl
->status
== Data::Implementation::STATUS_NEW
) {
1126 // Postpone actual implementation instantiation as long as
1127 // possible (so that e.g. opening LO's "Tools - Macros" menu
1128 // does not try to instantiate a JVM, which can lead to a
1129 // synchronous error dialog when no JVM is specified, and
1130 // showing the dialog while hovering over a menu can cause
1132 impl
->factory1
= new ImplementationWrapper(this, rxImpl
);
1133 impl
->status
= Data::Implementation::STATUS_WRAPPER
;
1135 if (impl
->constructor
!= nullptr && !impl
->factory1
.is()) {
1136 impl
->factory1
= new ImplementationWrapper(this, rxImpl
);
1139 if (impl
->factory1
.is()) {
1140 factories
.push_back(css::uno::Any(impl
->factory1
));
1142 assert(impl
->factory2
.is());
1143 factories
.push_back(css::uno::Any(impl
->factory2
));
1146 return new ContentEnumeration(factories
);
1149 css::uno::Reference
< css::beans::XPropertySetInfo
>
1150 cppuhelper::ServiceManager::getPropertySetInfo()
1155 void cppuhelper::ServiceManager::setPropertyValue(
1156 OUString
const & aPropertyName
, css::uno::Any
const &)
1158 if (aPropertyName
== "DefaultContext") {
1159 throw css::beans::PropertyVetoException(
1160 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1162 throw css::beans::UnknownPropertyException(
1163 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1167 css::uno::Any
cppuhelper::ServiceManager::getPropertyValue(
1168 OUString
const & PropertyName
)
1170 if (PropertyName
!= "DefaultContext") {
1171 throw css::beans::UnknownPropertyException(
1172 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1174 assert(context_
.is());
1175 return css::uno::Any(context_
);
1178 void cppuhelper::ServiceManager::addPropertyChangeListener(
1179 OUString
const & aPropertyName
,
1180 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
1183 if (!aPropertyName
.isEmpty() && aPropertyName
!= "DefaultContext") {
1184 throw css::beans::UnknownPropertyException(
1185 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1187 // DefaultContext does not change, so just treat it as an event listener:
1188 return addEventListener(xListener
);
1191 void cppuhelper::ServiceManager::removePropertyChangeListener(
1192 OUString
const & aPropertyName
,
1193 css::uno::Reference
< css::beans::XPropertyChangeListener
> const &
1196 if (!aPropertyName
.isEmpty() && aPropertyName
!= "DefaultContext") {
1197 throw css::beans::UnknownPropertyException(
1198 aPropertyName
, static_cast< cppu::OWeakObject
* >(this));
1200 // DefaultContext does not change, so just treat it as an event listener:
1201 return removeEventListener(aListener
);
1204 void cppuhelper::ServiceManager::addVetoableChangeListener(
1205 OUString
const & PropertyName
,
1206 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
1209 if (!PropertyName
.isEmpty() && PropertyName
!= "DefaultContext") {
1210 throw css::beans::UnknownPropertyException(
1211 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1213 // DefaultContext does not change, so just treat it as an event listener:
1214 return addEventListener(aListener
);
1217 void cppuhelper::ServiceManager::removeVetoableChangeListener(
1218 OUString
const & PropertyName
,
1219 css::uno::Reference
< css::beans::XVetoableChangeListener
> const &
1222 if (!PropertyName
.isEmpty() && PropertyName
!= "DefaultContext") {
1223 throw css::beans::UnknownPropertyException(
1224 PropertyName
, static_cast< cppu::OWeakObject
* >(this));
1226 // DefaultContext does not change, so just treat it as an event listener:
1227 return removeEventListener(aListener
);
1230 css::uno::Sequence
< css::beans::Property
>
1231 cppuhelper::ServiceManager::getProperties() {
1232 css::uno::Sequence
< css::beans::Property
> props(1);
1233 props
[0] = getDefaultContextProperty();
1237 css::beans::Property
cppuhelper::ServiceManager::getPropertyByName(
1238 OUString
const & aName
)
1240 if (aName
!= "DefaultContext") {
1241 throw css::beans::UnknownPropertyException(
1242 aName
, static_cast< cppu::OWeakObject
* >(this));
1244 return getDefaultContextProperty();
1247 sal_Bool
cppuhelper::ServiceManager::hasPropertyByName(
1248 OUString
const & Name
)
1250 return Name
== "DefaultContext";
1253 cppuhelper::ServiceManager::~ServiceManager() {}
1255 void cppuhelper::ServiceManager::disposing(
1256 css::lang::EventObject
const & Source
)
1258 removeLegacyFactory(
1259 css::uno::Reference
< css::lang::XServiceInfo
>(
1260 Source
.Source
, css::uno::UNO_QUERY_THROW
),
1264 void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1265 css::uno::Reference
< css::lang::XComponent
> const & component
)
1267 assert(component
.is());
1269 component
->removeEventListener(this);
1270 } catch (css::uno::RuntimeException
& e
) {
1273 "Ignored removeEventListener RuntimeException " + e
.Message
);
1277 void cppuhelper::ServiceManager::init(OUString
const & rdbUris
) {
1278 for (sal_Int32 i
= 0; i
!= -1;) {
1279 OUString
uri(rdbUris
.getToken(0, ' ', i
));
1280 if (uri
.isEmpty()) {
1285 cppu::decodeRdbUri(&uri
, &optional
, &directory
);
1287 readRdbDirectory(uri
, optional
);
1289 readRdbFile(uri
, optional
);
1294 void cppuhelper::ServiceManager::readRdbDirectory(
1295 OUString
const & uri
, bool optional
)
1297 osl::Directory
dir(uri
);
1298 switch (dir
.open()) {
1299 case osl::FileBase::E_None
:
1301 case osl::FileBase::E_NOENT
:
1303 SAL_INFO("cppuhelper", "Ignored optional " << uri
);
1308 throw css::uno::DeploymentException(
1309 "Cannot open directory " + uri
,
1310 static_cast< cppu::OWeakObject
* >(this));
1314 if (!cppu::nextDirectoryItem(dir
, &url
)) {
1317 readRdbFile(url
, false);
1321 void cppuhelper::ServiceManager::readRdbFile(
1322 OUString
const & uri
, bool optional
)
1326 uri
, css::uno::Reference
< css::uno::XComponentContext
>(), &data_
);
1327 } catch (css::container::NoSuchElementException
&) {
1329 throw css::uno::DeploymentException(
1330 uri
+ ": no such file",
1331 static_cast< cppu::OWeakObject
* >(this));
1333 SAL_INFO("cppuhelper", "Ignored optional " << uri
);
1334 } catch (css::registry::InvalidRegistryException
& e
) {
1335 if (!readLegacyRdbFile(uri
)) {
1336 throw css::uno::DeploymentException(
1337 "InvalidRegistryException: " + e
.Message
,
1338 static_cast< cppu::OWeakObject
* >(this));
1340 } catch (css::uno::RuntimeException
&) {
1341 if (!readLegacyRdbFile(uri
)) {
1347 bool cppuhelper::ServiceManager::readLegacyRdbFile(OUString
const & uri
) {
1349 switch (reg
.open(uri
, RegAccessMode::READONLY
)) {
1350 case RegError::NO_ERROR
:
1352 case RegError::REGISTRY_NOT_EXISTS
:
1353 case RegError::INVALID_REGISTRY
:
1355 // Ignore empty rdb files (which are at least seen by subordinate
1356 // uno processes during extension registration; Registry::open can
1357 // fail on them if mmap(2) returns EINVAL for a zero length):
1358 osl::DirectoryItem item
;
1359 if (osl::DirectoryItem::get(uri
, item
) == osl::FileBase::E_None
) {
1360 osl::FileStatus
status(osl_FileStatus_Mask_FileSize
);
1361 if (item
.getFileStatus(status
) == osl::FileBase::E_None
1362 && status
.getFileSize() == 0)
1372 RegistryKey rootKey
;
1373 if (reg
.openRootKey(rootKey
) != RegError::NO_ERROR
) {
1374 throw css::uno::DeploymentException(
1375 "Failure reading legacy rdb file " + uri
,
1376 static_cast< cppu::OWeakObject
* >(this));
1378 RegistryKeyArray impls
;
1379 switch (rootKey
.openSubKeys("IMPLEMENTATIONS", impls
)) {
1380 case RegError::NO_ERROR
:
1382 case RegError::KEY_NOT_EXISTS
:
1385 throw css::uno::DeploymentException(
1386 "Failure reading legacy rdb file " + uri
,
1387 static_cast< cppu::OWeakObject
* >(this));
1389 for (sal_uInt32 i
= 0; i
!= impls
.getLength(); ++i
) {
1390 RegistryKey
implKey(impls
.getElement(i
));
1391 assert(implKey
.getName().match("/IMPLEMENTATIONS/"));
1393 implKey
.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1394 std::shared_ptr
< Data::Implementation
> impl(
1395 new Data::Implementation(
1396 name
, readLegacyRdbString(uri
, implKey
, "UNO/ACTIVATOR"),
1397 readLegacyRdbString(uri
, implKey
, "UNO/LOCATION"), "", "", "",
1398 css::uno::Reference
< css::uno::XComponentContext
>(), uri
));
1399 if (!data_
.namedImplementations
.emplace(name
, impl
).second
)
1401 throw css::registry::InvalidRegistryException(
1402 uri
+ ": duplicate <implementation name=\"" + name
+ "\">");
1404 readLegacyRdbStrings(
1405 uri
, implKey
, "UNO/SERVICES", &impl
->info
->services
);
1406 for (const auto& rService
: impl
->info
->services
)
1408 data_
.services
[rService
].push_back(impl
);
1410 readLegacyRdbStrings(
1411 uri
, implKey
, "UNO/SINGLETONS", &impl
->info
->singletons
);
1412 for (const auto& rSingleton
: impl
->info
->singletons
)
1414 data_
.singletons
[rSingleton
].push_back(impl
);
1420 OUString
cppuhelper::ServiceManager::readLegacyRdbString(
1421 OUString
const & uri
, RegistryKey
& key
, OUString
const & path
)
1426 if (key
.openKey(path
, subkey
) != RegError::NO_ERROR
1427 || subkey
.getValueInfo(OUString(), &t
, &s
) != RegError::NO_ERROR
1428 || t
!= RegValueType::STRING
1429 || s
== 0 || s
> static_cast< sal_uInt32
>(SAL_MAX_INT32
))
1431 throw css::uno::DeploymentException(
1432 "Failure reading legacy rdb file " + uri
,
1433 static_cast< cppu::OWeakObject
* >(this));
1436 std::vector
< char > v(s
); // assuming sal_uInt32 fits into vector::size_type
1437 if (subkey
.getValue(OUString(), v
.data()) != RegError::NO_ERROR
1439 || !rtl_convertStringToUString(
1440 &val
.pData
, v
.data(), static_cast< sal_Int32
>(s
- 1),
1441 RTL_TEXTENCODING_UTF8
,
1442 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1443 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1444 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR
)))
1446 throw css::uno::DeploymentException(
1447 "Failure reading legacy rdb file " + uri
,
1448 static_cast< cppu::OWeakObject
* >(this));
1453 void cppuhelper::ServiceManager::readLegacyRdbStrings(
1454 OUString
const & uri
, RegistryKey
& key
, OUString
const & path
,
1455 std::vector
< OUString
> * strings
)
1457 assert(strings
!= nullptr);
1459 switch (key
.openKey(path
, subkey
)) {
1460 case RegError::NO_ERROR
:
1462 case RegError::KEY_NOT_EXISTS
:
1465 throw css::uno::DeploymentException(
1466 "Failure reading legacy rdb file " + uri
,
1467 static_cast< cppu::OWeakObject
* >(this));
1469 OUString
prefix(subkey
.getName() + "/");
1470 RegistryKeyNames names
;
1471 if (subkey
.getKeyNames(OUString(), names
) != RegError::NO_ERROR
) {
1472 throw css::uno::DeploymentException(
1473 "Failure reading legacy rdb file " + uri
,
1474 static_cast< cppu::OWeakObject
* >(this));
1476 for (sal_uInt32 i
= 0; i
!= names
.getLength(); ++i
) {
1477 assert(names
.getElement(i
).match(prefix
));
1478 strings
->push_back(names
.getElement(i
).copy(prefix
.getLength()));
1482 void cppuhelper::ServiceManager::insertRdbFiles(
1483 std::vector
< OUString
> const & uris
,
1484 css::uno::Reference
< css::uno::XComponentContext
> const & alienContext
)
1487 for (const auto& rUri
: uris
)
1490 Parser(rUri
, alienContext
, &extra
);
1491 } catch (css::container::NoSuchElementException
&) {
1492 throw css::lang::IllegalArgumentException(
1493 rUri
+ ": no such file", static_cast< cppu::OWeakObject
* >(this),
1495 } catch (css::registry::InvalidRegistryException
& e
) {
1496 throw css::lang::IllegalArgumentException(
1497 "InvalidRegistryException: " + e
.Message
,
1498 static_cast< cppu::OWeakObject
* >(this), 0);
1501 insertExtraData(extra
);
1504 void cppuhelper::ServiceManager::insertLegacyFactory(
1505 css::uno::Reference
< css::lang::XServiceInfo
> const & factoryInfo
)
1507 assert(factoryInfo
.is());
1508 OUString
name(factoryInfo
->getImplementationName());
1509 css::uno::Reference
< css::lang::XSingleComponentFactory
> f1(
1510 factoryInfo
, css::uno::UNO_QUERY
);
1511 css::uno::Reference
< css::lang::XSingleServiceFactory
> f2
;
1513 f2
.set(factoryInfo
, css::uno::UNO_QUERY
);
1515 throw css::lang::IllegalArgumentException(
1516 ("Bad XServiceInfo argument implements neither"
1517 " XSingleComponentFactory nor XSingleServiceFactory"),
1518 static_cast< cppu::OWeakObject
* >(this), 0);
1521 css::uno::Reference
< css::lang::XComponent
> comp(
1522 factoryInfo
, css::uno::UNO_QUERY
);
1523 std::shared_ptr
< Data::Implementation
> impl(
1524 new Data::Implementation(name
, f1
, f2
, comp
));
1526 if (!name
.isEmpty()) {
1527 extra
.namedImplementations
.emplace(name
, impl
);
1529 extra
.dynamicImplementations
.emplace(factoryInfo
, impl
);
1530 css::uno::Sequence
< OUString
> services(
1531 factoryInfo
->getSupportedServiceNames());
1532 for (sal_Int32 i
= 0; i
!= services
.getLength(); ++i
) {
1533 impl
->info
->services
.push_back(services
[i
]);
1534 extra
.services
[services
[i
]].push_back(impl
);
1536 if (insertExtraData(extra
) && comp
.is()) {
1537 comp
->addEventListener(this);
1541 bool cppuhelper::ServiceManager::insertExtraData(Data
const & extra
) {
1543 osl::MutexGuard
g(rBHelper
.rMutex
);
1547 auto i
= std::find_if(extra
.namedImplementations
.begin(), extra
.namedImplementations
.end(),
1548 [this](const Data::NamedImplementations::value_type
& rEntry
) {
1549 return data_
.namedImplementations
.find(rEntry
.first
) != data_
.namedImplementations
.end(); });
1550 if (i
!= extra
.namedImplementations
.end())
1552 throw css::lang::IllegalArgumentException(
1553 "Insert duplicate implementation name " + i
->first
,
1554 static_cast< cppu::OWeakObject
* >(this), 0);
1556 bool bDuplicate
= std::any_of(extra
.dynamicImplementations
.begin(), extra
.dynamicImplementations
.end(),
1557 [this](const Data::DynamicImplementations::value_type
& rEntry
) {
1558 return data_
.dynamicImplementations
.find(rEntry
.first
) != data_
.dynamicImplementations
.end(); });
1561 throw css::lang::IllegalArgumentException(
1562 "Insert duplicate factory object",
1563 static_cast< cppu::OWeakObject
* >(this), 0);
1565 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1566 data_
.namedImplementations
.insert(
1567 extra
.namedImplementations
.begin(),
1568 extra
.namedImplementations
.end());
1569 data_
.dynamicImplementations
.insert(
1570 extra
.dynamicImplementations
.begin(),
1571 extra
.dynamicImplementations
.end());
1572 insertImplementationMap(&data_
.services
, extra
.services
);
1573 insertImplementationMap(&data_
.singletons
, extra
.singletons
);
1575 //TODO: Updating the component context singleton data should be part of the
1576 // atomic service manager update:
1577 if (!extra
.singletons
.empty()) {
1578 assert(context_
.is());
1579 css::uno::Reference
< css::container::XNameContainer
> cont(
1580 context_
, css::uno::UNO_QUERY_THROW
);
1581 for (const auto& [rName
, rImpls
] : extra
.singletons
)
1583 OUString
name("/singletons/" + rName
);
1584 //TODO: Update should be atomic:
1586 cont
->removeByName(name
+ "/arguments");
1587 } catch (const css::container::NoSuchElementException
&) {}
1588 assert(!rImpls
.empty());
1589 assert(rImpls
[0].get() != nullptr);
1591 rImpls
.size() > 1, "cppuhelper",
1592 "Arbitrarily choosing " << rImpls
[0]->info
->name
1593 << " among multiple implementations for singleton "
1597 name
+ "/service", css::uno::Any(rImpls
[0]->info
->name
));
1598 } catch (css::container::ElementExistException
&) {
1599 cont
->replaceByName(
1600 name
+ "/service", css::uno::Any(rImpls
[0]->info
->name
));
1603 cont
->insertByName(name
, css::uno::Any());
1604 } catch (css::container::ElementExistException
&) {
1605 SAL_INFO("cppuhelper", "Overwriting singleton " << rName
);
1606 cont
->replaceByName(name
, css::uno::Any());
1613 void cppuhelper::ServiceManager::removeRdbFiles(
1614 std::vector
< OUString
> const & uris
)
1616 // The underlying data structures make this function somewhat inefficient,
1617 // but the assumption is that it is rarely called (and that if it is called,
1618 // it is called with a uris vector of size one):
1619 std::vector
< std::shared_ptr
< Data::Implementation
> > clear
;
1621 osl::MutexGuard
g(rBHelper
.rMutex
);
1622 for (const auto& rUri
: uris
)
1624 for (Data::NamedImplementations::iterator
j(
1625 data_
.namedImplementations
.begin());
1626 j
!= data_
.namedImplementations
.end();)
1628 assert(j
->second
.get() != nullptr);
1629 if (j
->second
->info
->rdbFile
== rUri
) {
1630 clear
.push_back(j
->second
);
1631 //TODO: The below leaves data_ in an inconsistent state upon
1633 removeFromImplementationMap(
1634 &data_
.services
, j
->second
->info
->services
, j
->second
);
1635 removeFromImplementationMap(
1636 &data_
.singletons
, j
->second
->info
->singletons
,
1638 j
= data_
.namedImplementations
.erase(j
);
1645 //TODO: Update the component context singleton data
1648 bool cppuhelper::ServiceManager::removeLegacyFactory(
1649 css::uno::Reference
< css::lang::XServiceInfo
> const & factoryInfo
,
1650 bool removeListener
)
1652 assert(factoryInfo
.is());
1653 std::shared_ptr
< Data::Implementation
> clear
;
1654 css::uno::Reference
< css::lang::XComponent
> comp
;
1656 osl::MutexGuard
g(rBHelper
.rMutex
);
1657 Data::DynamicImplementations::iterator
i(
1658 data_
.dynamicImplementations
.find(factoryInfo
));
1659 if (i
== data_
.dynamicImplementations
.end()) {
1660 return isDisposed();
1662 assert(i
->second
.get() != nullptr);
1664 if (removeListener
) {
1665 comp
= i
->second
->component
;
1667 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1668 removeFromImplementationMap(
1669 &data_
.services
, i
->second
->info
->services
, i
->second
);
1670 removeFromImplementationMap(
1671 &data_
.singletons
, i
->second
->info
->singletons
, i
->second
);
1672 if (!i
->second
->info
->name
.isEmpty()) {
1673 data_
.namedImplementations
.erase(i
->second
->info
->name
);
1675 data_
.dynamicImplementations
.erase(i
);
1678 removeEventListenerFromComponent(comp
);
1683 void cppuhelper::ServiceManager::removeImplementation(const OUString
& name
) {
1684 // The underlying data structures make this function somewhat inefficient,
1685 // but the assumption is that it is rarely called:
1686 std::shared_ptr
< Data::Implementation
> clear
;
1688 osl::MutexGuard
g(rBHelper
.rMutex
);
1692 Data::NamedImplementations::iterator
i(
1693 data_
.namedImplementations
.find(name
));
1694 if (i
== data_
.namedImplementations
.end()) {
1695 throw css::container::NoSuchElementException(
1696 "Remove non-inserted implementation " + name
,
1697 static_cast< cppu::OWeakObject
* >(this));
1699 assert(i
->second
.get() != nullptr);
1701 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1702 removeFromImplementationMap(
1703 &data_
.services
, i
->second
->info
->services
, i
->second
);
1704 removeFromImplementationMap(
1705 &data_
.singletons
, i
->second
->info
->singletons
, i
->second
);
1706 auto j
= std::find_if(data_
.dynamicImplementations
.begin(), data_
.dynamicImplementations
.end(),
1707 [&i
](const Data::DynamicImplementations::value_type
& rEntry
) { return rEntry
.second
== i
->second
; });
1708 if (j
!= data_
.dynamicImplementations
.end())
1709 data_
.dynamicImplementations
.erase(j
);
1710 data_
.namedImplementations
.erase(i
);
1714 std::shared_ptr
< cppuhelper::ServiceManager::Data::Implementation
>
1715 cppuhelper::ServiceManager::findServiceImplementation(
1716 css::uno::Reference
< css::uno::XComponentContext
> const & context
,
1717 OUString
const & specifier
)
1719 std::shared_ptr
< Data::Implementation
> impl
;
1722 osl::MutexGuard
g(rBHelper
.rMutex
);
1723 Data::ImplementationMap::const_iterator
i(
1724 data_
.services
.find(specifier
));
1725 if (i
== data_
.services
.end()) {
1726 Data::NamedImplementations::const_iterator
j(
1727 data_
.namedImplementations
.find(specifier
));
1728 if (j
== data_
.namedImplementations
.end()) {
1729 SAL_INFO("cppuhelper", "No implementation for " << specifier
);
1730 return std::shared_ptr
< Data::Implementation
>();
1734 assert(!i
->second
.empty());
1736 i
->second
.size() > 1, "cppuhelper",
1737 "Arbitrarily choosing " << i
->second
[0]->info
->name
1738 << " among multiple implementations for " << i
->first
);
1739 impl
= i
->second
[0];
1741 assert(impl
.get() != nullptr);
1742 loaded
= impl
->status
== Data::Implementation::STATUS_LOADED
;
1745 loadImplementation(context
, impl
);
1750 /// Make a simpler unique name for preload / progress reporting.
1751 #ifndef DISABLE_DYNLOADING
1752 static OUString
simplifyModule(const OUString
&uri
)
1755 OUStringBuffer
edit(uri
);
1756 if ((nIdx
= edit
.lastIndexOf('/')) > 0)
1757 edit
.remove(0,nIdx
+1);
1758 if ((nIdx
= edit
.lastIndexOf(':')) > 0)
1759 edit
.remove(0,nIdx
+1);
1760 if ((nIdx
= edit
.lastIndexOf("lo.so")) > 0)
1761 edit
.truncate(nIdx
);
1762 if ((nIdx
= edit
.lastIndexOf(".3")) > 0)
1763 edit
.truncate(nIdx
);
1764 if ((nIdx
= edit
.lastIndexOf("gcc3.so")) > 0)
1765 edit
.truncate(nIdx
);
1766 if ((nIdx
= edit
.lastIndexOf(".so")) > 0)
1767 edit
.truncate(nIdx
);
1768 if ((nIdx
= edit
.lastIndexOf("_uno")) > 0)
1769 edit
.truncate(nIdx
);
1770 if ((nIdx
= edit
.lastIndexOf(".jar")) > 0)
1771 edit
.truncate(nIdx
);
1772 if (edit
.indexOf("lib") == 0)
1774 return edit
.makeStringAndClear();
1778 /// Used only by LibreOfficeKit when used by Online to pre-initialize
1779 void cppuhelper::ServiceManager::preloadImplementations() {
1780 #ifdef DISABLE_DYNLOADING
1784 osl::MutexGuard
g(rBHelper
.rMutex
);
1785 css::uno::Environment
aSourceEnv(css::uno::Environment::getCurrent());
1787 std::cerr
<< "preload:";
1788 std::vector
<OUString
> aReported
;
1789 std::vector
<OUString
> aDisabled
;
1790 OUStringBuffer aDisabledMsg
;
1792 /// Allow external callers & testers to disable certain components
1793 const char *pDisable
= getenv("UNODISABLELIBRARY");
1796 OUString
aDisable(pDisable
, strlen(pDisable
), RTL_TEXTENCODING_UTF8
);
1797 for (sal_Int32 i
= 0; i
>= 0; )
1799 OUString tok
= aDisable
.getToken(0, ' ', i
);
1802 aDisabled
.push_back(tok
);
1806 // loop all implementations
1807 for (const auto& rEntry
: data_
.namedImplementations
)
1809 if (rEntry
.second
->info
->loader
!= "com.sun.star.loader.SharedLibrary" ||
1810 rEntry
.second
->status
== Data::Implementation::STATUS_LOADED
)
1815 const OUString
&aLibrary
= rEntry
.second
->info
->uri
;
1817 if (aLibrary
.isEmpty())
1820 OUString simplified
= simplifyModule(aLibrary
);
1822 std::find(aDisabled
.begin(), aDisabled
.end(), simplified
) != aDisabled
.end();
1824 if (std::find(aReported
.begin(), aReported
.end(), aLibrary
) == aReported
.end())
1828 aDisabledMsg
.append(simplified
);
1829 aDisabledMsg
.append(" ");
1833 std::cerr
<< " " << simplified
;
1836 aReported
.push_back(aLibrary
);
1842 // expand absolute URI implementation component library
1843 aUri
= cppu::bootstrap_expandUri(aLibrary
);
1845 catch (css::lang::IllegalArgumentException
& aError
)
1847 throw css::uno::DeploymentException(
1848 "Cannot expand URI" + rEntry
.second
->info
->uri
+ ": " + aError
.Message
,
1849 static_cast< cppu::OWeakObject
* >(this));
1852 // load component library
1853 osl::Module
aModule(aUri
, SAL_LOADMODULE_NOW
| SAL_LOADMODULE_GLOBAL
);
1857 std::cerr
<< ":failed" << std::endl
;
1862 !rEntry
.second
->info
->environment
.isEmpty())
1864 OUString aSymFactory
;
1865 oslGenericFunction fpFactory
;
1866 css::uno::Environment aTargetEnv
;
1867 css::uno::Reference
<css::uno::XInterface
> xFactory
;
1869 if(rEntry
.second
->info
->constructor
.isEmpty())
1871 // expand full name component factory symbol
1872 if (rEntry
.second
->info
->prefix
== "direct")
1873 aSymFactory
= rEntry
.second
->info
->name
.replace('.', '_') + "_" COMPONENT_GETFACTORY
;
1874 else if (!rEntry
.second
->info
->prefix
.isEmpty())
1875 aSymFactory
= rEntry
.second
->info
->prefix
+ "_" COMPONENT_GETFACTORY
;
1877 aSymFactory
= COMPONENT_GETFACTORY
;
1879 // get function symbol component factory
1880 fpFactory
= aModule
.getFunctionSymbol(aSymFactory
);
1881 if (fpFactory
== nullptr)
1883 throw css::loader::CannotActivateFactoryException(
1884 ("no factory symbol \"" + aSymFactory
+ "\" in component library :" + aUri
),
1885 css::uno::Reference
<css::uno::XInterface
>());
1888 aTargetEnv
= cppuhelper::detail::getEnvironment(rEntry
.second
->info
->environment
, rEntry
.second
->info
->name
);
1889 component_getFactoryFunc fpComponentFactory
= reinterpret_cast<component_getFactoryFunc
>(fpFactory
);
1891 if (aSourceEnv
.get() == aTargetEnv
.get())
1893 // invoke function component factory
1894 OString
aImpl(OUStringToOString(rEntry
.second
->info
->name
, RTL_TEXTENCODING_ASCII_US
));
1895 xFactory
.set(css::uno::Reference
<css::uno::XInterface
>(static_cast<css::uno::XInterface
*>(
1896 (*fpComponentFactory
)(aImpl
.getStr(), this, nullptr)), SAL_NO_ACQUIRE
));
1901 // get function symbol component factory
1902 aTargetEnv
= cppuhelper::detail::getEnvironment(rEntry
.second
->info
->environment
, rEntry
.second
->info
->name
);
1903 fpFactory
= (aSourceEnv
.get() == aTargetEnv
.get()) ?
1904 aModule
.getFunctionSymbol(rEntry
.second
->info
->constructor
) : nullptr;
1907 css::uno::Reference
<css::lang::XSingleComponentFactory
> xSCFactory
;
1908 css::uno::Reference
<css::lang::XSingleServiceFactory
> xSSFactory
;
1910 // query interface XSingleComponentFactory or XSingleServiceFactory
1913 xSCFactory
.set(xFactory
, css::uno::UNO_QUERY
);
1914 if (!xSCFactory
.is())
1916 xSSFactory
.set(xFactory
, css::uno::UNO_QUERY
);
1917 if (!xSSFactory
.is())
1918 throw css::uno::DeploymentException(
1919 ("Implementation " + rEntry
.second
->info
->name
1920 + " does not provide a constructor or factory"),
1921 static_cast< cppu::OWeakObject
* >(this));
1925 if (!rEntry
.second
->info
->constructor
.isEmpty() && fpFactory
)
1926 rEntry
.second
->constructor
= WrapperConstructorFn(reinterpret_cast<ImplementationConstructorFn
*>(fpFactory
));
1928 rEntry
.second
->factory1
= xSCFactory
;
1929 rEntry
.second
->factory2
= xSSFactory
;
1930 rEntry
.second
->status
= Data::Implementation::STATUS_LOADED
;
1934 // Some libraries use other (non-UNO) libraries requiring preinit
1935 oslGenericFunction fpPreload
= aModule
.getFunctionSymbol( "lok_preload_hook" );
1938 static std::vector
<oslGenericFunction
> aPreloaded
;
1939 if (std::find(aPreloaded
.begin(), aPreloaded
.end(), fpPreload
) == aPreloaded
.end())
1941 aPreloaded
.push_back(fpPreload
);
1949 std::cerr
<< std::endl
;
1951 if (aDisabledMsg
.getLength() > 0)
1953 OUString aMsg
= aDisabledMsg
.makeStringAndClear();
1954 std::cerr
<< "Disabled: " << aMsg
<< "\n";
1958 // Various rather important uno mappings.
1962 const char *mpPurpose
;
1963 } const aMappingLoad
[] = {
1964 { "gcc3", "uno", "" },
1965 { "uno", "gcc3", "" },
1968 static std::vector
<css::uno::Mapping
> maMaps
;
1969 for (auto &it
: aMappingLoad
)
1971 maMaps
.push_back(css::uno::Mapping(
1972 OUString::createFromAscii(it
.mpFrom
),
1973 OUString::createFromAscii(it
.mpTo
),
1974 OUString::createFromAscii(it
.mpPurpose
)));
1979 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */