Bump version to 5.0-14
[LibreOffice.git] / cppuhelper / source / servicemanager.cxx
blob2140a2f74f07f2deb764faeadfe7882e33ea694f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sal/config.h>
12 #include <algorithm>
13 #include <cassert>
14 #include <vector>
16 #include <boost/noncopyable.hpp>
17 #include <boost/shared_ptr.hpp>
18 #include <boost/weak_ptr.hpp>
19 #include <com/sun/star/beans/NamedValue.hpp>
20 #include <com/sun/star/beans/PropertyAttribute.hpp>
21 #include <com/sun/star/container/ElementExistException.hpp>
22 #include <com/sun/star/container/XEnumeration.hpp>
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/lang/XInitialization.hpp>
25 #include <com/sun/star/lang/XServiceInfo.hpp>
26 #include <com/sun/star/lang/XSingleComponentFactory.hpp>
27 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
28 #include <com/sun/star/loader/XImplementationLoader.hpp>
29 #include <com/sun/star/registry/InvalidRegistryException.hpp>
30 #include <com/sun/star/uno/DeploymentException.hpp>
31 #include <com/sun/star/uno/Reference.hxx>
32 #include <com/sun/star/uno/XComponentContext.hpp>
33 #include <cppuhelper/bootstrap.hxx>
34 #include <cppuhelper/component_context.hxx>
35 #include <cppuhelper/implbase1.hxx>
36 #include <cppuhelper/implbase3.hxx>
37 #include <cppuhelper/supportsservice.hxx>
38 #include <osl/file.hxx>
39 #include <rtl/ref.hxx>
40 #include <rtl/uri.hxx>
41 #include <rtl/ustring.hxx>
42 #include <rtl/strbuf.hxx>
43 #include <sal/log.hxx>
44 #include <uno/environment.hxx>
46 #include "loadsharedlibcomponentfactory.hxx"
48 using rtl::OUString;
49 using rtl::OString;
50 using rtl::OStringBuffer;
52 #include <registry/registry.hxx>
53 #include <xmlreader/xmlreader.hxx>
55 #include "paths.hxx"
56 #include "servicemanager.hxx"
58 namespace {
60 void insertImplementationMap(
61 cppuhelper::ServiceManager::Data::ImplementationMap * destination,
62 cppuhelper::ServiceManager::Data::ImplementationMap const & source)
64 assert(destination != 0);
65 for (cppuhelper::ServiceManager::Data::ImplementationMap::const_iterator i(
66 source.begin());
67 i != source.end(); ++i)
69 std::vector<
70 boost::shared_ptr<
71 cppuhelper::ServiceManager::Data::Implementation > > & impls
72 = (*destination)[i->first];
73 impls.insert(impls.end(), i->second.begin(), i->second.end());
77 void removeFromImplementationMap(
78 cppuhelper::ServiceManager::Data::ImplementationMap * map,
79 std::vector< rtl::OUString > const & elements,
80 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
81 const & implementation)
83 // The underlying data structures make this function somewhat inefficient,
84 // but the assumption is that it is rarely called:
85 assert(map != 0);
86 for (std::vector< rtl::OUString >::const_iterator i(elements.begin());
87 i != elements.end(); ++i)
89 cppuhelper::ServiceManager::Data::ImplementationMap::iterator j(
90 map->find(*i));
91 assert(j != map->end());
92 std::vector<
93 boost::shared_ptr<
94 cppuhelper::ServiceManager::Data::Implementation > >::iterator
95 k(std::find(j->second.begin(), j->second.end(), implementation));
96 assert(k != j->second.end());
97 j->second.erase(k);
98 if (j->second.empty()) {
99 map->erase(j);
104 // For simplicity, this code keeps throwing
105 // css::registry::InvalidRegistryException for invalid XML rdbs (even though
106 // that does not fit the exception's name):
107 class Parser: private boost::noncopyable {
108 public:
109 Parser(
110 rtl::OUString const & uri,
111 css::uno::Reference< css::uno::XComponentContext > const & alienContext,
112 cppuhelper::ServiceManager::Data * data);
114 private:
115 void handleComponent();
117 void handleImplementation();
119 void handleService();
121 void handleSingleton();
123 rtl::OUString getNameAttribute();
125 xmlreader::XmlReader reader_;
126 css::uno::Reference< css::uno::XComponentContext > alienContext_;
127 cppuhelper::ServiceManager::Data * data_;
128 rtl::OUString attrLoader_;
129 rtl::OUString attrUri_;
130 rtl::OUString attrEnvironment_;
131 rtl::OUString attrPrefix_;
132 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
133 implementation_;
136 Parser::Parser(
137 rtl::OUString const & uri,
138 css::uno::Reference< css::uno::XComponentContext > const & alienContext,
139 cppuhelper::ServiceManager::Data * data):
140 reader_(uri), alienContext_(alienContext), data_(data)
142 assert(data != 0);
143 int ucNsId = reader_.registerNamespaceIri(
144 xmlreader::Span(
145 RTL_CONSTASCII_STRINGPARAM(
146 "http://openoffice.org/2010/uno-components")));
147 enum State {
148 STATE_BEGIN, STATE_END, STATE_COMPONENTS, STATE_COMPONENT_INITIAL,
149 STATE_COMPONENT, STATE_IMPLEMENTATION, STATE_SERVICE, STATE_SINGLETON };
150 for (State state = STATE_BEGIN;;) {
151 xmlreader::Span name;
152 int nsId;
153 xmlreader::XmlReader::Result res = reader_.nextItem(
154 xmlreader::XmlReader::TEXT_NONE, &name, &nsId);
155 switch (state) {
156 case STATE_BEGIN:
157 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
158 && name.equals(RTL_CONSTASCII_STRINGPARAM("components")))
160 state = STATE_COMPONENTS;
161 break;
163 throw css::registry::InvalidRegistryException(
164 reader_.getUrl() + ": unexpected item in outer level");
165 case STATE_END:
166 if (res == xmlreader::XmlReader::RESULT_DONE) {
167 return;
169 throw css::registry::InvalidRegistryException(
170 reader_.getUrl() + ": unexpected item in outer level");
171 case STATE_COMPONENTS:
172 if (res == xmlreader::XmlReader::RESULT_END) {
173 state = STATE_END;
174 break;
176 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
177 && name.equals(RTL_CONSTASCII_STRINGPARAM("component")))
179 handleComponent();
180 state = STATE_COMPONENT_INITIAL;
181 break;
183 throw css::registry::InvalidRegistryException(
184 reader_.getUrl() + ": unexpected item in <components>");
185 case STATE_COMPONENT:
186 if (res == xmlreader::XmlReader::RESULT_END) {
187 state = STATE_COMPONENTS;
188 break;
190 // fall through
191 case STATE_COMPONENT_INITIAL:
192 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
193 && name.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
195 handleImplementation();
196 state = STATE_IMPLEMENTATION;
197 break;
199 throw css::registry::InvalidRegistryException(
200 reader_.getUrl() + ": unexpected item in <component>");
201 case STATE_IMPLEMENTATION:
202 if (res == xmlreader::XmlReader::RESULT_END) {
203 state = STATE_COMPONENT;
204 break;
206 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
207 && name.equals(RTL_CONSTASCII_STRINGPARAM("service")))
209 handleService();
210 state = STATE_SERVICE;
211 break;
213 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
214 && name.equals(RTL_CONSTASCII_STRINGPARAM("singleton")))
216 handleSingleton();
217 state = STATE_SINGLETON;
218 break;
220 throw css::registry::InvalidRegistryException(
221 reader_.getUrl() + ": unexpected item in <implementation>");
222 case STATE_SERVICE:
223 if (res == xmlreader::XmlReader::RESULT_END) {
224 state = STATE_IMPLEMENTATION;
225 break;
227 throw css::registry::InvalidRegistryException(
228 reader_.getUrl() + ": unexpected item in <service>");
229 case STATE_SINGLETON:
230 if (res == xmlreader::XmlReader::RESULT_END) {
231 state = STATE_IMPLEMENTATION;
232 break;
234 throw css::registry::InvalidRegistryException(
235 reader_.getUrl() + ": unexpected item in <service>");
240 void Parser::handleComponent() {
241 attrLoader_ = rtl::OUString();
242 attrUri_ = rtl::OUString();
243 attrEnvironment_ = rtl::OUString();
244 attrPrefix_ = rtl::OUString();
245 xmlreader::Span name;
246 int nsId;
247 while (reader_.nextAttribute(&nsId, &name)) {
248 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
249 && name.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
251 if (!attrLoader_.isEmpty()) {
252 throw css::registry::InvalidRegistryException(
253 reader_.getUrl()
254 + ": <component> has multiple \"loader\" attributes");
256 attrLoader_ = reader_.getAttributeValue(false).convertFromUtf8();
257 if (attrLoader_.isEmpty()) {
258 throw css::registry::InvalidRegistryException(
259 reader_.getUrl()
260 + ": <component> has empty \"loader\" attribute");
262 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
263 && name.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
265 if (!attrUri_.isEmpty()) {
266 throw css::registry::InvalidRegistryException(
267 reader_.getUrl()
268 + ": <component> has multiple \"uri\" attributes");
270 attrUri_ = reader_.getAttributeValue(false).convertFromUtf8();
271 if (attrUri_.isEmpty()) {
272 throw css::registry::InvalidRegistryException(
273 reader_.getUrl()
274 + ": <component> has empty \"uri\" attribute");
276 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
277 && name.equals(RTL_CONSTASCII_STRINGPARAM("environment")))
279 if (!attrEnvironment_.isEmpty()) {
280 throw css::registry::InvalidRegistryException(
281 reader_.getUrl() +
282 ": <component> has multiple \"environment\" attributes");
284 attrEnvironment_ = reader_.getAttributeValue(false)
285 .convertFromUtf8();
286 if (attrEnvironment_.isEmpty()) {
287 throw css::registry::InvalidRegistryException(
288 reader_.getUrl() +
289 ": <component> has empty \"environment\" attribute");
291 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
292 && name.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
294 if (!attrPrefix_.isEmpty()) {
295 throw css::registry::InvalidRegistryException(
296 reader_.getUrl() +
297 ": <component> has multiple \"prefix\" attributes");
299 attrPrefix_ = reader_.getAttributeValue(false).convertFromUtf8();
300 if (attrPrefix_.isEmpty()) {
301 throw css::registry::InvalidRegistryException(
302 reader_.getUrl() +
303 ": <component> has empty \"prefix\" attribute");
305 } else {
306 throw css::registry::InvalidRegistryException(
307 reader_.getUrl() + ": unexpected attribute \""
308 + name.convertFromUtf8() + "\" in <component>");
311 if (attrLoader_.isEmpty()) {
312 throw css::registry::InvalidRegistryException(
313 reader_.getUrl() + ": <component> is missing \"loader\" attribute");
315 if (attrUri_.isEmpty()) {
316 throw css::registry::InvalidRegistryException(
317 reader_.getUrl() + ": <component> is missing \"uri\" attribute");
319 #ifndef DISABLE_DYNLOADING
320 try {
321 attrUri_ = rtl::Uri::convertRelToAbs(reader_.getUrl(), attrUri_);
322 } catch (const rtl::MalformedUriException & e) {
323 throw css::registry::InvalidRegistryException(
324 reader_.getUrl() + ": bad \"uri\" attribute: " + e.getMessage());
326 #endif
329 void Parser::handleImplementation() {
330 rtl::OUString attrName;
331 rtl::OUString attrConstructor;
332 xmlreader::Span name;
333 int nsId;
334 while (reader_.nextAttribute(&nsId, &name)) {
335 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
336 && name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
338 if (!attrName.isEmpty()) {
339 throw css::registry::InvalidRegistryException(
340 reader_.getUrl()
341 + ": <implementation> has multiple \"name\" attributes");
343 attrName = reader_.getAttributeValue(false).convertFromUtf8();
344 if (attrName.isEmpty()) {
345 throw css::registry::InvalidRegistryException(
346 reader_.getUrl()
347 + ": <implementation> has empty \"name\" attribute");
349 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
350 && name.equals(RTL_CONSTASCII_STRINGPARAM("constructor")))
352 if (!attrConstructor.isEmpty()) {
353 throw css::registry::InvalidRegistryException(
354 reader_.getUrl()
355 + ": <implementation> has multiple \"constructor\""
356 " attributes");
358 attrConstructor = reader_.getAttributeValue(false)
359 .convertFromUtf8();
360 if (attrConstructor.isEmpty()) {
361 throw css::registry::InvalidRegistryException(
362 reader_.getUrl()
363 + ": element has empty \"constructor\" attribute");
365 if (attrEnvironment_.isEmpty()) {
366 throw css::registry::InvalidRegistryException(
367 reader_.getUrl()
368 + ": <implementation> has \"constructor\" attribute but"
369 " <component> has no \"environment\" attribute");
371 } else {
372 throw css::registry::InvalidRegistryException(
373 reader_.getUrl() + ": unexpected element attribute \""
374 + name.convertFromUtf8() + "\" in <implementation>");
377 if (attrName.isEmpty()) {
378 throw css::registry::InvalidRegistryException(
379 reader_.getUrl()
380 + ": <implementation> is missing \"name\" attribute");
382 implementation_.reset(
383 new cppuhelper::ServiceManager::Data::Implementation(
384 attrName, attrLoader_, attrUri_, attrEnvironment_, attrConstructor,
385 attrPrefix_, alienContext_, reader_.getUrl()));
386 if (!data_->namedImplementations.insert(
387 cppuhelper::ServiceManager::Data::NamedImplementations::value_type(
388 attrName, implementation_)).
389 second)
391 throw css::registry::InvalidRegistryException(
392 reader_.getUrl() + ": duplicate <implementation name=\"" + attrName
393 + "\">");
397 void Parser::handleService() {
398 rtl::OUString name(getNameAttribute());
399 implementation_->info->services.push_back(name);
400 data_->services[name].push_back(implementation_);
403 void Parser::handleSingleton() {
404 rtl::OUString name(getNameAttribute());
405 implementation_->info->singletons.push_back(name);
406 data_->singletons[name].push_back(implementation_);
409 rtl::OUString Parser::getNameAttribute() {
410 rtl::OUString attrName;
411 xmlreader::Span name;
412 int nsId;
413 while (reader_.nextAttribute(&nsId, &name)) {
414 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
415 && name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
417 if (!attrName.isEmpty()) {
418 throw css::registry::InvalidRegistryException(
419 reader_.getUrl()
420 + ": element has multiple \"name\" attributes");
422 attrName = reader_.getAttributeValue(false).convertFromUtf8();
423 if (attrName.isEmpty()) {
424 throw css::registry::InvalidRegistryException(
425 reader_.getUrl() + ": element has empty \"name\" attribute");
427 } else {
428 throw css::registry::InvalidRegistryException(
429 reader_.getUrl() + ": expected element attribute \"name\"");
432 if (attrName.isEmpty()) {
433 throw css::registry::InvalidRegistryException(
434 reader_.getUrl() + ": element is missing \"name\" attribute");
436 return attrName;
439 class ContentEnumeration:
440 public cppu::WeakImplHelper1< css::container::XEnumeration >,
441 private boost::noncopyable
443 public:
444 explicit ContentEnumeration(std::vector< css::uno::Any > const & factories):
445 factories_(factories), iterator_(factories_.begin()) {}
447 private:
448 virtual ~ContentEnumeration() {}
450 virtual sal_Bool SAL_CALL hasMoreElements()
451 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
453 virtual css::uno::Any SAL_CALL nextElement()
454 throw (
455 css::container::NoSuchElementException,
456 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
458 osl::Mutex mutex_;
459 std::vector< css::uno::Any > factories_;
460 std::vector< css::uno::Any >::const_iterator iterator_;
463 sal_Bool ContentEnumeration::hasMoreElements()
464 throw (css::uno::RuntimeException, std::exception)
466 osl::MutexGuard g(mutex_);
467 return iterator_ != factories_.end();
470 css::uno::Any ContentEnumeration::nextElement()
471 throw (
472 css::container::NoSuchElementException,
473 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
475 osl::MutexGuard g(mutex_);
476 if (iterator_ == factories_.end()) {
477 throw css::container::NoSuchElementException(
478 "Bootstrap service manager service enumerator has no more elements",
479 static_cast< cppu::OWeakObject * >(this));
481 return *iterator_++;
484 css::beans::Property getDefaultContextProperty() {
485 return css::beans::Property(
486 "DefaultContext", -1,
487 cppu::UnoType< css::uno::XComponentContext >::get(),
488 css::beans::PropertyAttribute::READONLY);
491 class SingletonFactory:
492 public cppu::WeakImplHelper1<css::lang::XSingleComponentFactory>,
493 private boost::noncopyable
495 public:
496 SingletonFactory(
497 rtl::Reference< cppuhelper::ServiceManager > const & manager,
498 boost::shared_ptr<
499 cppuhelper::ServiceManager::Data::Implementation > const &
500 implementation):
501 manager_(manager), implementation_(implementation)
502 { assert(manager.is()); assert(implementation.get() != 0); }
504 private:
505 virtual ~SingletonFactory() {}
507 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
508 createInstanceWithContext(
509 css::uno::Reference< css::uno::XComponentContext > const & Context)
510 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
512 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
513 createInstanceWithArgumentsAndContext(
514 css::uno::Sequence< css::uno::Any > const & Arguments,
515 css::uno::Reference< css::uno::XComponentContext > const & Context)
516 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
518 rtl::Reference< cppuhelper::ServiceManager > manager_;
519 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
520 implementation_;
523 css::uno::Reference< css::uno::XInterface >
524 SingletonFactory::createInstanceWithContext(
525 css::uno::Reference< css::uno::XComponentContext > const & Context)
526 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
528 manager_->loadImplementation(Context, implementation_);
529 return implementation_->createInstance(Context, true);
532 css::uno::Reference< css::uno::XInterface >
533 SingletonFactory::createInstanceWithArgumentsAndContext(
534 css::uno::Sequence< css::uno::Any > const & Arguments,
535 css::uno::Reference< css::uno::XComponentContext > const & Context)
536 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
538 manager_->loadImplementation(Context, implementation_);
539 return implementation_->createInstanceWithArguments(
540 Context, true, Arguments);
543 class ImplementationWrapper:
544 public cppu::WeakImplHelper3<
545 css::lang::XSingleComponentFactory, css::lang::XSingleServiceFactory,
546 css::lang::XServiceInfo >,
547 private boost::noncopyable
549 public:
550 ImplementationWrapper(
551 rtl::Reference< cppuhelper::ServiceManager > const & manager,
552 boost::shared_ptr<
553 cppuhelper::ServiceManager::Data::Implementation > const &
554 implementation):
555 manager_(manager), implementation_(implementation)
556 { assert(manager.is()); assert(implementation.get() != 0); }
558 private:
559 virtual ~ImplementationWrapper() {}
561 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
562 createInstanceWithContext(
563 css::uno::Reference< css::uno::XComponentContext > const & Context)
564 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
566 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
567 createInstanceWithArgumentsAndContext(
568 css::uno::Sequence< css::uno::Any > const & Arguments,
569 css::uno::Reference< css::uno::XComponentContext > const & Context)
570 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
572 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
573 createInstance() throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
575 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
576 createInstanceWithArguments(
577 css::uno::Sequence< css::uno::Any > const & Arguments)
578 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
580 virtual rtl::OUString SAL_CALL getImplementationName()
581 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
583 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName)
584 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
586 virtual css::uno::Sequence< rtl::OUString > SAL_CALL
587 getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
589 rtl::Reference< cppuhelper::ServiceManager > manager_;
590 boost::weak_ptr< cppuhelper::ServiceManager::Data::Implementation >
591 implementation_;
594 css::uno::Reference< css::uno::XInterface >
595 ImplementationWrapper::createInstanceWithContext(
596 css::uno::Reference< css::uno::XComponentContext > const & Context)
597 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
599 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
600 assert(impl);
601 manager_->loadImplementation(Context, impl);
602 return impl->createInstance(Context, false);
605 css::uno::Reference< css::uno::XInterface >
606 ImplementationWrapper::createInstanceWithArgumentsAndContext(
607 css::uno::Sequence< css::uno::Any > const & Arguments,
608 css::uno::Reference< css::uno::XComponentContext > const & Context)
609 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
611 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
612 assert(impl);
613 manager_->loadImplementation(Context, impl);
614 return impl->createInstanceWithArguments(
615 Context, false, Arguments);
618 css::uno::Reference< css::uno::XInterface >
619 ImplementationWrapper::createInstance()
620 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
622 return createInstanceWithContext(manager_->getContext());
625 css::uno::Reference< css::uno::XInterface >
626 ImplementationWrapper::createInstanceWithArguments(
627 css::uno::Sequence< css::uno::Any > const & Arguments)
628 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
630 return createInstanceWithArgumentsAndContext(
631 Arguments, manager_->getContext());
634 rtl::OUString ImplementationWrapper::getImplementationName()
635 throw (css::uno::RuntimeException, std::exception)
637 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
638 assert(impl);
639 return impl->info->name;
642 sal_Bool ImplementationWrapper::supportsService(rtl::OUString const & ServiceName)
643 throw (css::uno::RuntimeException, std::exception)
645 return cppu::supportsService(this, ServiceName);
648 css::uno::Sequence< rtl::OUString >
649 ImplementationWrapper::getSupportedServiceNames()
650 throw (css::uno::RuntimeException, std::exception)
652 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation > impl = implementation_.lock();
653 assert(impl);
654 if (impl->info->services.size()
655 > static_cast< sal_uInt32 >(SAL_MAX_INT32))
657 throw css::uno::RuntimeException(
658 ("Implementation " + impl->info->name
659 + " supports too many services"),
660 static_cast< cppu::OWeakObject * >(this));
662 css::uno::Sequence< rtl::OUString > names(
663 static_cast< sal_Int32 >(impl->info->services.size()));
664 sal_Int32 i = 0;
665 for (std::vector< rtl::OUString >::const_iterator j(
666 impl->info->services.begin());
667 j != impl->info->services.end(); ++j)
669 names[i++] = *j;
671 return names;
676 css::uno::Reference<css::uno::XInterface>
677 cppuhelper::ServiceManager::Data::Implementation::createInstance(
678 css::uno::Reference<css::uno::XComponentContext> const & context,
679 bool singletonRequest)
681 css::uno::Reference<css::uno::XInterface> inst;
682 if (constructor != 0) {
683 inst.set(
684 (*constructor)(context.get(), css::uno::Sequence<css::uno::Any>()),
685 SAL_NO_ACQUIRE);
686 } else if (factory1.is()) {
687 inst = factory1->createInstanceWithContext(context);
688 } else {
689 assert(factory2.is());
690 inst = factory2->createInstance();
692 updateDisposeSingleton(singletonRequest, inst);
693 return inst;
696 css::uno::Reference<css::uno::XInterface>
697 cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments(
698 css::uno::Reference<css::uno::XComponentContext> const & context,
699 bool singletonRequest, css::uno::Sequence<css::uno::Any> const & arguments)
701 css::uno::Reference<css::uno::XInterface> inst;
702 if (constructor != 0) {
703 inst.set((*constructor)(context.get(), arguments), SAL_NO_ACQUIRE);
704 //HACK: The constructor will either observe arguments and return inst
705 // that does not implement XInitialization (or null), or ignore
706 // arguments and return inst that implements XInitialization; this
707 // should be removed again once XInitialization-based implementations
708 // have become rare:
709 css::uno::Reference<css::lang::XInitialization> init(
710 inst, css::uno::UNO_QUERY);
711 if (init.is()) {
712 init->initialize(arguments);
714 } else if (factory1.is()) {
715 inst = factory1->createInstanceWithArgumentsAndContext(
716 arguments, context);
717 } else {
718 assert(factory2.is());
719 inst = factory2->createInstanceWithArguments(arguments);
721 updateDisposeSingleton(singletonRequest, inst);
722 return inst;
725 void cppuhelper::ServiceManager::Data::Implementation::updateDisposeSingleton(
726 bool singletonRequest,
727 css::uno::Reference<css::uno::XInterface> const & instance)
729 // This is an optimization, to only call dispose once (from the component
730 // context) on a singleton that is obtained both via the component context
731 // and via the service manager; however, there is a harmless race here that
732 // may cause two calls to dispose nevertheless (also, this calls dispose on
733 // at most one of the instances obtained via the service manager, in case
734 // the implementation hands out different instances):
735 if (singletonRequest) {
736 osl::MutexGuard g(mutex);
737 disposeSingleton.clear();
738 dispose = false;
739 } else if (!info->singletons.empty()) {
740 css::uno::Reference<css::lang::XComponent> comp(
741 instance, css::uno::UNO_QUERY);
742 if (comp.is()) {
743 osl::MutexGuard g(mutex);
744 if (dispose) {
745 disposeSingleton = comp;
751 void cppuhelper::ServiceManager::addSingletonContextEntries(
752 std::vector< cppu::ContextEntry_Init > * entries)
754 assert(entries != 0);
755 for (Data::ImplementationMap::const_iterator i(data_.singletons.begin());
756 i != data_.singletons.end(); ++i)
758 assert(!i->second.empty());
759 assert(i->second[0].get() != 0);
760 SAL_INFO_IF(
761 i->second.size() > 1, "cppuhelper",
762 "Arbitrarily chosing " << i->second[0]->info->name
763 << " among multiple implementations for " << i->first);
764 entries->push_back(
765 cppu::ContextEntry_Init(
766 "/singletons/" + i->first,
767 css::uno::makeAny<
768 css::uno::Reference<css::lang::XSingleComponentFactory> >(
769 new SingletonFactory(this, i->second[0])),
770 true));
774 void cppuhelper::ServiceManager::loadImplementation(
775 css::uno::Reference< css::uno::XComponentContext > const & context,
776 boost::shared_ptr< Data::Implementation > & implementation)
778 assert(implementation.get() != 0);
780 osl::MutexGuard g(rBHelper.rMutex);
781 if (implementation->status == Data::Implementation::STATUS_LOADED) {
782 return;
785 rtl::OUString uri;
786 try {
787 uri = cppu::bootstrap_expandUri(implementation->info->uri);
788 } catch (css::lang::IllegalArgumentException & e) {
789 throw css::uno::DeploymentException(
790 "Cannot expand URI" + implementation->info->uri + ": " + e.Message,
791 static_cast< cppu::OWeakObject * >(this));
793 cppuhelper::ImplementationConstructorFn * ctor = 0;
794 css::uno::Reference< css::uno::XInterface > f0;
795 // Special handling of SharedLibrary loader, with support for environment,
796 // constructor, and prefix arguments:
797 if (!implementation->info->alienContext.is()
798 && implementation->info->loader == "com.sun.star.loader.SharedLibrary")
800 cppuhelper::detail::loadSharedLibComponentFactory(
801 uri, implementation->info->environment,
802 implementation->info->prefix, implementation->info->name,
803 implementation->info->constructor, this, &ctor, &f0);
804 if (ctor != 0) {
805 assert(!implementation->info->environment.isEmpty());
806 css::uno::Environment curEnv(css::uno::Environment::getCurrent());
807 css::uno::Environment env(
808 cppuhelper::detail::getEnvironment(
809 implementation->info->environment,
810 implementation->info->name));
811 if (!(curEnv.is() && env.is())) {
812 throw css::uno::DeploymentException(
813 "cannot get environments",
814 css::uno::Reference<css::uno::XInterface>());
816 if (curEnv.get() != env.get()) {
817 std::abort();//TODO
820 } else {
821 SAL_WARN_IF(
822 !implementation->info->environment.isEmpty(), "cppuhelper",
823 "Loader " << implementation->info->loader
824 << " and non-empty environment "
825 << implementation->info->environment);
826 SAL_WARN_IF(
827 !implementation->info->prefix.isEmpty(), "cppuhelper",
828 "Loader " << implementation->info->loader
829 << " and non-empty constructor "
830 << implementation->info->constructor);
831 SAL_WARN_IF(
832 !implementation->info->prefix.isEmpty(), "cppuhelper",
833 "Loader " << implementation->info->loader
834 << " and non-empty prefix " << implementation->info->prefix);
835 css::uno::Reference< css::uno::XComponentContext > ctxt;
836 css::uno::Reference< css::lang::XMultiComponentFactory > smgr;
837 if (implementation->info->alienContext.is()) {
838 ctxt = implementation->info->alienContext;
839 smgr = css::uno::Reference< css::lang::XMultiComponentFactory >(
840 ctxt->getServiceManager(), css::uno::UNO_SET_THROW);
841 } else {
842 assert(context.is());
843 ctxt = context;
844 smgr = this;
846 css::uno::Reference< css::loader::XImplementationLoader > loader(
847 smgr->createInstanceWithContext(implementation->info->loader, ctxt),
848 css::uno::UNO_QUERY_THROW);
849 f0 = loader->activate(
850 implementation->info->name, rtl::OUString(), uri,
851 css::uno::Reference< css::registry::XRegistryKey >());
853 css::uno::Reference<css::lang::XSingleComponentFactory> f1;
854 css::uno::Reference<css::lang::XSingleServiceFactory> f2;
855 if (ctor == 0) {
856 f1.set(f0, css::uno::UNO_QUERY);
857 if (!f1.is()) {
858 f2.set(f0, css::uno::UNO_QUERY);
859 if (!f2.is()) {
860 throw css::uno::DeploymentException(
861 ("Implementation " + implementation->info->name
862 + " does not provide a constructor or factory"),
863 static_cast< cppu::OWeakObject * >(this));
867 //TODO: There is a race here, as the relevant service factory can be removed
868 // while the mutex is unlocked and loading can thus fail, as the entity from
869 // which to load can disappear once the service factory is removed.
870 osl::MutexGuard g(rBHelper.rMutex);
871 if (!(isDisposed()
872 || implementation->status == Data::Implementation::STATUS_LOADED))
874 implementation->status = Data::Implementation::STATUS_LOADED;
875 implementation->constructor = ctor;
876 implementation->factory1 = f1;
877 implementation->factory2 = f2;
881 void cppuhelper::ServiceManager::disposing() {
882 std::vector< css::uno::Reference<css::lang::XComponent> > sngls;
883 std::vector< css::uno::Reference< css::lang::XComponent > > comps;
884 Data clear;
886 osl::MutexGuard g(rBHelper.rMutex);
887 for (Data::NamedImplementations::const_iterator i(
888 data_.namedImplementations.begin());
889 i != data_.namedImplementations.end(); ++i)
891 assert(i->second.get() != 0);
892 if (!i->second->info->singletons.empty()) {
893 osl::MutexGuard g2(i->second->mutex);
894 if (i->second->disposeSingleton.is()) {
895 sngls.push_back(i->second->disposeSingleton);
899 for (Data::DynamicImplementations::const_iterator i(
900 data_.dynamicImplementations.begin());
901 i != data_.dynamicImplementations.end(); ++i)
903 assert(i->second.get() != 0);
904 if (!i->second->info->singletons.empty()) {
905 osl::MutexGuard g2(i->second->mutex);
906 if (i->second->disposeSingleton.is()) {
907 sngls.push_back(i->second->disposeSingleton);
910 if (i->second->component.is()) {
911 comps.push_back(i->second->component);
914 data_.namedImplementations.swap(clear.namedImplementations);
915 data_.dynamicImplementations.swap(clear.dynamicImplementations);
916 data_.services.swap(clear.services);
917 data_.singletons.swap(clear.singletons);
919 for (std::vector<
920 css::uno::Reference<css::lang::XComponent> >::const_iterator i(
921 sngls.begin());
922 i != sngls.end(); ++i)
924 try {
925 (*i)->dispose();
926 } catch (css::uno::RuntimeException & e) {
927 SAL_WARN(
928 "cppuhelper",
929 "Ignoring RuntimeException \"" << e.Message
930 << "\" while disposing singleton");
933 for (std::vector<
934 css::uno::Reference< css::lang::XComponent > >::const_iterator i(
935 comps.begin());
936 i != comps.end(); ++i)
938 removeEventListenerFromComponent(*i);
942 rtl::OUString cppuhelper::ServiceManager::getImplementationName()
943 throw (css::uno::RuntimeException, std::exception)
945 return rtl::OUString(
946 "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager");
949 sal_Bool cppuhelper::ServiceManager::supportsService(
950 rtl::OUString const & ServiceName)
951 throw (css::uno::RuntimeException, std::exception)
953 return cppu::supportsService(this, ServiceName);
956 css::uno::Sequence< rtl::OUString >
957 cppuhelper::ServiceManager::getSupportedServiceNames()
958 throw (css::uno::RuntimeException, std::exception)
960 css::uno::Sequence< rtl::OUString > names(2);
961 names[0] = "com.sun.star.lang.MultiServiceFactory";
962 names[1] = "com.sun.star.lang.ServiceManager";
963 return names;
966 css::uno::Reference< css::uno::XInterface >
967 cppuhelper::ServiceManager::createInstance(
968 rtl::OUString const & aServiceSpecifier)
969 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
971 assert(context_.is());
972 return createInstanceWithContext(aServiceSpecifier, context_);
975 css::uno::Reference< css::uno::XInterface >
976 cppuhelper::ServiceManager::createInstanceWithArguments(
977 rtl::OUString const & ServiceSpecifier,
978 css::uno::Sequence< css::uno::Any > const & Arguments)
979 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
981 assert(context_.is());
982 return createInstanceWithArgumentsAndContext(
983 ServiceSpecifier, Arguments, context_);
986 css::uno::Sequence< rtl::OUString >
987 cppuhelper::ServiceManager::getAvailableServiceNames()
988 throw (css::uno::RuntimeException, std::exception)
990 osl::MutexGuard g(rBHelper.rMutex);
991 if (isDisposed()) {
992 return css::uno::Sequence< rtl::OUString >();
994 Data::ImplementationMap::size_type n = data_.services.size();
995 if (n > static_cast< sal_uInt32 >(SAL_MAX_INT32)) {
996 throw css::uno::RuntimeException(
997 "getAvailableServiceNames: too many services",
998 static_cast< cppu::OWeakObject * >(this));
1000 css::uno::Sequence< rtl::OUString > names(static_cast< sal_Int32 >(n));
1001 sal_Int32 i = 0;
1002 for (Data::ImplementationMap::const_iterator j(data_.services.begin());
1003 j != data_.services.end(); ++j)
1005 names[i++] = j->first;
1007 assert(i == names.getLength());
1008 return names;
1011 css::uno::Reference< css::uno::XInterface >
1012 cppuhelper::ServiceManager::createInstanceWithContext(
1013 rtl::OUString const & aServiceSpecifier,
1014 css::uno::Reference< css::uno::XComponentContext > const & Context)
1015 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
1017 boost::shared_ptr< Data::Implementation > impl(
1018 findServiceImplementation(Context, aServiceSpecifier));
1019 return impl.get() == 0
1020 ? css::uno::Reference< css::uno::XInterface >()
1021 : impl->createInstance(Context, false);
1024 css::uno::Reference< css::uno::XInterface >
1025 cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext(
1026 rtl::OUString const & ServiceSpecifier,
1027 css::uno::Sequence< css::uno::Any > const & Arguments,
1028 css::uno::Reference< css::uno::XComponentContext > const & Context)
1029 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
1031 boost::shared_ptr< Data::Implementation > impl(
1032 findServiceImplementation(Context, ServiceSpecifier));
1033 return impl.get() == 0
1034 ? css::uno::Reference< css::uno::XInterface >()
1035 : impl->createInstanceWithArguments(Context, false, Arguments);
1038 css::uno::Type cppuhelper::ServiceManager::getElementType()
1039 throw (css::uno::RuntimeException, std::exception)
1041 return css::uno::Type();
1044 sal_Bool cppuhelper::ServiceManager::hasElements()
1045 throw (css::uno::RuntimeException, std::exception)
1047 osl::MutexGuard g(rBHelper.rMutex);
1048 return
1049 !(data_.namedImplementations.empty()
1050 && data_.dynamicImplementations.empty());
1053 css::uno::Reference< css::container::XEnumeration >
1054 cppuhelper::ServiceManager::createEnumeration()
1055 throw (css::uno::RuntimeException, std::exception)
1057 throw css::uno::RuntimeException(
1058 "ServiceManager createEnumeration: method not supported",
1059 static_cast< cppu::OWeakObject * >(this));
1062 sal_Bool cppuhelper::ServiceManager::has(css::uno::Any const &)
1063 throw (css::uno::RuntimeException, std::exception)
1065 throw css::uno::RuntimeException(
1066 "ServiceManager has: method not supported",
1067 static_cast< cppu::OWeakObject * >(this));
1070 void cppuhelper::ServiceManager::insert(css::uno::Any const & aElement)
1071 throw (
1072 css::lang::IllegalArgumentException,
1073 css::container::ElementExistException, css::uno::RuntimeException, std::exception)
1075 css::uno::Sequence< css::beans::NamedValue > args;
1076 if (aElement >>= args) {
1077 std::vector< rtl::OUString > uris;
1078 css::uno::Reference< css::uno::XComponentContext > alienContext;
1079 for (sal_Int32 i = 0; i < args.getLength(); ++i) {
1080 if (args[i].Name == "uri") {
1081 rtl::OUString uri;
1082 if (!(args[i].Value >>= uri)) {
1083 throw css::lang::IllegalArgumentException(
1084 "Bad uri argument",
1085 static_cast< cppu::OWeakObject * >(this), 0);
1087 uris.push_back(uri);
1088 } else if (args[i].Name == "component-context") {
1089 if (alienContext.is()) {
1090 throw css::lang::IllegalArgumentException(
1091 "Multiple component-context arguments",
1092 static_cast< cppu::OWeakObject * >(this), 0);
1094 if (!(args[i].Value >>= alienContext) || !alienContext.is()) {
1095 throw css::lang::IllegalArgumentException(
1096 "Bad component-context argument",
1097 static_cast< cppu::OWeakObject * >(this), 0);
1099 } else {
1100 throw css::lang::IllegalArgumentException(
1101 "Bad argument " + args[i].Name,
1102 static_cast< cppu::OWeakObject * >(this), 0);
1105 insertRdbFiles(uris, alienContext);
1106 return;
1108 css::uno::Reference< css::lang::XServiceInfo > info;
1109 if ((aElement >>= info) && info.is()) {
1110 insertLegacyFactory(info);
1111 return;
1113 // At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in
1114 // module languagetool) contain an (actively registered) factory that does not
1115 // implement XServiceInfo (see <http://sourceforge.net/tracker/?
1116 // func=detail&aid=3526635&group_id=110216&atid=655717> "SingletonFactory should
1117 // implement XServiceInfo"); the old OServiceManager::insert
1118 // (stoc/source/servicemanager/servicemanager.cxx) silently did not add such
1119 // broken factories to its m_ImplementationNameMap, so ignore them here for
1120 // backwards compatibility of live-insertion of extensions, too.
1122 // (The plan was that this warning would go away (and we would do the
1123 // throw instead) for the incompatible LO 4, but we changed our mind):
1124 css::uno::Reference< css::lang::XSingleComponentFactory > legacy;
1125 if ((aElement >>= legacy) && legacy.is()) {
1126 SAL_WARN(
1127 "cppuhelper",
1128 "Ignored XSingleComponentFactory not implementing XServiceInfo");
1129 return;
1132 throw css::lang::IllegalArgumentException(
1133 "Bad insert element", static_cast< cppu::OWeakObject * >(this), 0);
1136 void cppuhelper::ServiceManager::remove(css::uno::Any const & aElement)
1137 throw (
1138 css::lang::IllegalArgumentException,
1139 css::container::NoSuchElementException, css::uno::RuntimeException, std::exception)
1141 css::uno::Sequence< css::beans::NamedValue > args;
1142 if (aElement >>= args) {
1143 std::vector< rtl::OUString > uris;
1144 for (sal_Int32 i = 0; i < args.getLength(); ++i) {
1145 if (args[i].Name == "uri") {
1146 rtl::OUString uri;
1147 if (!(args[i].Value >>= uri)) {
1148 throw css::lang::IllegalArgumentException(
1149 "Bad uri argument",
1150 static_cast< cppu::OWeakObject * >(this), 0);
1152 uris.push_back(uri);
1153 } else {
1154 throw css::lang::IllegalArgumentException(
1155 "Bad argument " + args[i].Name,
1156 static_cast< cppu::OWeakObject * >(this), 0);
1159 removeRdbFiles(uris);
1160 return;
1162 css::uno::Reference< css::lang::XServiceInfo > info;
1163 if ((aElement >>= info) && info.is()) {
1164 if (!removeLegacyFactory(info, true)) {
1165 throw css::container::NoSuchElementException(
1166 "Remove non-inserted factory object",
1167 static_cast< cppu::OWeakObject * >(this));
1169 return;
1171 rtl::OUString impl;
1172 if (aElement >>= impl) {
1173 // For live-removal of extensions:
1174 removeImplementation(impl);
1175 return;
1177 throw css::lang::IllegalArgumentException(
1178 "Bad remove element", static_cast< cppu::OWeakObject * >(this), 0);
1181 css::uno::Reference< css::container::XEnumeration >
1182 cppuhelper::ServiceManager::createContentEnumeration(
1183 rtl::OUString const & aServiceName)
1184 throw (css::uno::RuntimeException, std::exception)
1186 std::vector< boost::shared_ptr< Data::Implementation > > impls;
1188 osl::MutexGuard g(rBHelper.rMutex);
1189 Data::ImplementationMap::const_iterator i(
1190 data_.services.find(aServiceName));
1191 if (i != data_.services.end()) {
1192 impls = i->second;
1195 std::vector< css::uno::Any > factories;
1196 for (std::vector<
1197 boost::shared_ptr< Data::Implementation > >::const_iterator i(
1198 impls.begin());
1199 i != impls.end(); ++i)
1201 Data::Implementation * impl = i->get();
1202 assert(impl != 0);
1204 osl::MutexGuard g(rBHelper.rMutex);
1205 if (isDisposed()) {
1206 factories.clear();
1207 break;
1209 if (impl->status == Data::Implementation::STATUS_NEW) {
1210 // Postpone actual implementation instantiation as long as
1211 // possible (so that e.g. opening LO's "Tools - Macros" menu
1212 // does not try to instantiate a JVM, which can lead to a
1213 // synchronous error dialog when no JVM is specified, and
1214 // showing the dialog while hovering over a menu can cause
1215 // trouble):
1216 impl->factory1 = new ImplementationWrapper(this, *i);
1217 impl->status = Data::Implementation::STATUS_WRAPPER;
1220 if (impl->factory1.is()) {
1221 factories.push_back(css::uno::makeAny(impl->factory1));
1222 } else if (impl->factory2.is()) {
1223 factories.push_back(css::uno::makeAny(impl->factory2));
1224 } else {
1225 css::uno::Reference< css::lang::XSingleComponentFactory > factory(
1226 new ImplementationWrapper(this, *i));
1227 factories.push_back(css::uno::makeAny(factory));
1230 return new ContentEnumeration(factories);
1233 css::uno::Reference< css::beans::XPropertySetInfo >
1234 cppuhelper::ServiceManager::getPropertySetInfo()
1235 throw (css::uno::RuntimeException, std::exception)
1237 return this;
1240 void cppuhelper::ServiceManager::setPropertyValue(
1241 rtl::OUString const & aPropertyName, css::uno::Any const &)
1242 throw (
1243 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1244 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1245 css::uno::RuntimeException, std::exception)
1247 if (aPropertyName == "DefaultContext") {
1248 throw css::beans::PropertyVetoException(
1249 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1250 } else {
1251 throw css::beans::UnknownPropertyException(
1252 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1256 css::uno::Any cppuhelper::ServiceManager::getPropertyValue(
1257 rtl::OUString const & PropertyName)
1258 throw (
1259 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1260 css::uno::RuntimeException, std::exception)
1262 if (PropertyName != "DefaultContext") {
1263 throw css::beans::UnknownPropertyException(
1264 PropertyName, static_cast< cppu::OWeakObject * >(this));
1266 assert(context_.is());
1267 return css::uno::makeAny(context_);
1270 void cppuhelper::ServiceManager::addPropertyChangeListener(
1271 rtl::OUString const & aPropertyName,
1272 css::uno::Reference< css::beans::XPropertyChangeListener > const &
1273 xListener)
1274 throw (
1275 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1276 css::uno::RuntimeException, std::exception)
1278 if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1279 throw css::beans::UnknownPropertyException(
1280 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1282 // DefaultContext does not change, so just treat it as an event listener:
1283 return addEventListener(xListener);
1286 void cppuhelper::ServiceManager::removePropertyChangeListener(
1287 rtl::OUString const & aPropertyName,
1288 css::uno::Reference< css::beans::XPropertyChangeListener > const &
1289 aListener)
1290 throw (
1291 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1292 css::uno::RuntimeException, std::exception)
1294 if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1295 throw css::beans::UnknownPropertyException(
1296 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1298 // DefaultContext does not change, so just treat it as an event listener:
1299 return removeEventListener(aListener);
1302 void cppuhelper::ServiceManager::addVetoableChangeListener(
1303 rtl::OUString const & PropertyName,
1304 css::uno::Reference< css::beans::XVetoableChangeListener > const &
1305 aListener)
1306 throw (
1307 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1308 css::uno::RuntimeException, std::exception)
1310 if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1311 throw css::beans::UnknownPropertyException(
1312 PropertyName, static_cast< cppu::OWeakObject * >(this));
1314 // DefaultContext does not change, so just treat it as an event listener:
1315 return addEventListener(aListener);
1318 void cppuhelper::ServiceManager::removeVetoableChangeListener(
1319 rtl::OUString const & PropertyName,
1320 css::uno::Reference< css::beans::XVetoableChangeListener > const &
1321 aListener)
1322 throw (
1323 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1324 css::uno::RuntimeException, std::exception)
1326 if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1327 throw css::beans::UnknownPropertyException(
1328 PropertyName, static_cast< cppu::OWeakObject * >(this));
1330 // DefaultContext does not change, so just treat it as an event listener:
1331 return removeEventListener(aListener);
1334 css::uno::Sequence< css::beans::Property >
1335 cppuhelper::ServiceManager::getProperties() throw (css::uno::RuntimeException, std::exception) {
1336 css::uno::Sequence< css::beans::Property > props(1);
1337 props[0] = getDefaultContextProperty();
1338 return props;
1341 css::beans::Property cppuhelper::ServiceManager::getPropertyByName(
1342 rtl::OUString const & aName)
1343 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException, std::exception)
1345 if (aName != "DefaultContext") {
1346 throw css::beans::UnknownPropertyException(
1347 aName, static_cast< cppu::OWeakObject * >(this));
1349 return getDefaultContextProperty();
1352 sal_Bool cppuhelper::ServiceManager::hasPropertyByName(
1353 rtl::OUString const & Name)
1354 throw (css::uno::RuntimeException, std::exception)
1356 return Name == "DefaultContext";
1359 void cppuhelper::ServiceManager::disposing(
1360 css::lang::EventObject const & Source)
1361 throw (css::uno::RuntimeException, std::exception)
1363 removeLegacyFactory(
1364 css::uno::Reference< css::lang::XServiceInfo >(
1365 Source.Source, css::uno::UNO_QUERY_THROW),
1366 false);
1369 void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1370 css::uno::Reference< css::lang::XComponent > const & component)
1372 assert(component.is());
1373 try {
1374 component->removeEventListener(this);
1375 } catch (css::uno::RuntimeException & e) {
1376 SAL_INFO(
1377 "cppuhelper",
1378 "Ignored removeEventListener RuntimeException " + e.Message);
1382 void cppuhelper::ServiceManager::readRdbs(rtl::OUString const & uris) {
1383 for (sal_Int32 i = 0; i != -1;) {
1384 rtl::OUString uri(uris.getToken(0, ' ', i));
1385 if (uri.isEmpty()) {
1386 continue;
1388 bool optional;
1389 bool directory;
1390 cppu::decodeRdbUri(&uri, &optional, &directory);
1391 if (directory) {
1392 readRdbDirectory(uri, optional);
1393 } else {
1394 readRdbFile(uri, optional);
1399 void cppuhelper::ServiceManager::readRdbDirectory(
1400 rtl::OUString const & uri, bool optional)
1402 osl::Directory dir(uri);
1403 switch (dir.open()) {
1404 case osl::FileBase::E_None:
1405 break;
1406 case osl::FileBase::E_NOENT:
1407 if (optional) {
1408 SAL_INFO("cppuhelper", "Ignored optional " << uri);
1409 return;
1411 // fall through
1412 default:
1413 throw css::uno::DeploymentException(
1414 "Cannot open directory " + uri,
1415 static_cast< cppu::OWeakObject * >(this));
1417 for (;;) {
1418 rtl::OUString url;
1419 if (!cppu::nextDirectoryItem(dir, &url)) {
1420 break;
1422 readRdbFile(url, false);
1426 void cppuhelper::ServiceManager::readRdbFile(
1427 rtl::OUString const & uri, bool optional)
1429 try {
1430 Parser(
1431 uri, css::uno::Reference< css::uno::XComponentContext >(), &data_);
1432 } catch (css::container::NoSuchElementException &) {
1433 if (!optional) {
1434 throw css::uno::DeploymentException(
1435 uri + ": no such file",
1436 static_cast< cppu::OWeakObject * >(this));
1438 SAL_INFO("cppuhelper", "Ignored optional " << uri);
1439 } catch (css::registry::InvalidRegistryException & e) {
1440 if (!readLegacyRdbFile(uri)) {
1441 throw css::uno::DeploymentException(
1442 "InvalidRegistryException: " + e.Message,
1443 static_cast< cppu::OWeakObject * >(this));
1445 } catch (css::uno::RuntimeException &) {
1446 if (!readLegacyRdbFile(uri)) {
1447 throw;
1452 bool cppuhelper::ServiceManager::readLegacyRdbFile(rtl::OUString const & uri) {
1453 Registry reg;
1454 switch (reg.open(uri, RegAccessMode::READONLY)) {
1455 case RegError::NO_ERROR:
1456 break;
1457 case RegError::REGISTRY_NOT_EXISTS:
1458 case RegError::INVALID_REGISTRY:
1460 // Ignore empty rdb files (which are at least seen by subordinate
1461 // uno processes during extension registration; Registry::open can
1462 // fail on them if mmap(2) returns EINVAL for a zero length):
1463 osl::DirectoryItem item;
1464 if (osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None) {
1465 osl::FileStatus status(osl_FileStatus_Mask_FileSize);
1466 if (item.getFileStatus(status) == osl::FileBase::E_None
1467 && status.getFileSize() == 0)
1469 return true;
1473 // fall through
1474 default:
1475 return false;
1477 RegistryKey rootKey;
1478 if (reg.openRootKey(rootKey) != RegError::NO_ERROR) {
1479 throw css::uno::DeploymentException(
1480 "Failure reading legacy rdb file " + uri,
1481 static_cast< cppu::OWeakObject * >(this));
1483 RegistryKeyArray impls;
1484 switch (rootKey.openSubKeys("IMPLEMENTATIONS", impls)) {
1485 case RegError::NO_ERROR:
1486 break;
1487 case RegError::KEY_NOT_EXISTS:
1488 return true;
1489 default:
1490 throw css::uno::DeploymentException(
1491 "Failure reading legacy rdb file " + uri,
1492 static_cast< cppu::OWeakObject * >(this));
1494 for (sal_uInt32 i = 0; i != impls.getLength(); ++i) {
1495 RegistryKey implKey(impls.getElement(i));
1496 assert(implKey.getName().match("/IMPLEMENTATIONS/"));
1497 rtl::OUString name(
1498 implKey.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1499 boost::shared_ptr< Data::Implementation > impl(
1500 new Data::Implementation(
1501 name, readLegacyRdbString(uri, implKey, "UNO/ACTIVATOR"),
1502 readLegacyRdbString(uri, implKey, "UNO/LOCATION"), "", "", "",
1503 css::uno::Reference< css::uno::XComponentContext >(), uri));
1504 if (!data_.namedImplementations.insert(
1505 Data::NamedImplementations::value_type(name, impl)).
1506 second)
1508 throw css::registry::InvalidRegistryException(
1509 uri + ": duplicate <implementation name=\"" + name + "\">");
1511 readLegacyRdbStrings(
1512 uri, implKey, "UNO/SERVICES", &impl->info->services);
1513 for (std::vector< rtl::OUString >::const_iterator j(
1514 impl->info->services.begin());
1515 j != impl->info->services.end(); ++j)
1517 data_.services[*j].push_back(impl);
1519 readLegacyRdbStrings(
1520 uri, implKey, "UNO/SINGLETONS", &impl->info->singletons);
1521 for (std::vector< rtl::OUString >::const_iterator j(
1522 impl->info->singletons.begin());
1523 j != impl->info->singletons.end(); ++j)
1525 data_.singletons[*j].push_back(impl);
1528 return true;
1531 rtl::OUString cppuhelper::ServiceManager::readLegacyRdbString(
1532 rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path)
1534 RegistryKey subkey;
1535 RegValueType t;
1536 sal_uInt32 s(0);
1537 if (key.openKey(path, subkey) != RegError::NO_ERROR
1538 || subkey.getValueInfo(rtl::OUString(), &t, &s) != RegError::NO_ERROR
1539 || t != RegValueType::STRING
1540 || s == 0 || s > static_cast< sal_uInt32 >(SAL_MAX_INT32))
1542 throw css::uno::DeploymentException(
1543 "Failure reading legacy rdb file " + uri,
1544 static_cast< cppu::OWeakObject * >(this));
1546 rtl::OUString val;
1547 std::vector< char > v(s); // assuming sal_uInt32 fits into vector::size_type
1548 if (subkey.getValue(rtl::OUString(), &v[0]) != RegError::NO_ERROR
1549 || v.back() != '\0'
1550 || !rtl_convertStringToUString(
1551 &val.pData, &v[0], static_cast< sal_Int32 >(s - 1),
1552 RTL_TEXTENCODING_UTF8,
1553 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1554 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1555 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
1557 throw css::uno::DeploymentException(
1558 "Failure reading legacy rdb file " + uri,
1559 static_cast< cppu::OWeakObject * >(this));
1561 return val;
1564 void cppuhelper::ServiceManager::readLegacyRdbStrings(
1565 rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path,
1566 std::vector< rtl::OUString > * strings)
1568 assert(strings != 0);
1569 RegistryKey subkey;
1570 switch (key.openKey(path, subkey)) {
1571 case RegError::NO_ERROR:
1572 break;
1573 case RegError::KEY_NOT_EXISTS:
1574 return;
1575 default:
1576 throw css::uno::DeploymentException(
1577 "Failure reading legacy rdb file " + uri,
1578 static_cast< cppu::OWeakObject * >(this));
1580 rtl::OUString prefix(subkey.getName() + "/");
1581 RegistryKeyNames names;
1582 if (subkey.getKeyNames(rtl::OUString(), names) != RegError::NO_ERROR) {
1583 throw css::uno::DeploymentException(
1584 "Failure reading legacy rdb file " + uri,
1585 static_cast< cppu::OWeakObject * >(this));
1587 for (sal_uInt32 i = 0; i != names.getLength(); ++i) {
1588 assert(names.getElement(i).match(prefix));
1589 strings->push_back(names.getElement(i).copy(prefix.getLength()));
1593 void cppuhelper::ServiceManager::insertRdbFiles(
1594 std::vector< rtl::OUString > const & uris,
1595 css::uno::Reference< css::uno::XComponentContext > const & alienContext)
1597 Data extra;
1598 for (std::vector< rtl::OUString >::const_iterator i(uris.begin());
1599 i != uris.end(); ++i)
1601 try {
1602 Parser(*i, alienContext, &extra);
1603 } catch (css::container::NoSuchElementException &) {
1604 throw css::lang::IllegalArgumentException(
1605 *i + ": no such file", static_cast< cppu::OWeakObject * >(this),
1607 } catch (css::registry::InvalidRegistryException & e) {
1608 throw css::lang::IllegalArgumentException(
1609 "InvalidRegistryException: " + e.Message,
1610 static_cast< cppu::OWeakObject * >(this), 0);
1613 insertExtraData(extra);
1616 void cppuhelper::ServiceManager::insertLegacyFactory(
1617 css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo)
1619 assert(factoryInfo.is());
1620 rtl::OUString name(factoryInfo->getImplementationName());
1621 css::uno::Reference< css::lang::XSingleComponentFactory > f1(
1622 factoryInfo, css::uno::UNO_QUERY);
1623 css::uno::Reference< css::lang::XSingleServiceFactory > f2;
1624 if (!f1.is()) {
1625 f2 = css::uno::Reference< css::lang::XSingleServiceFactory >(
1626 factoryInfo, css::uno::UNO_QUERY);
1627 if (!f2.is()) {
1628 throw css::lang::IllegalArgumentException(
1629 ("Bad XServiceInfo argument implements neither"
1630 " XSingleComponentFactory nor XSingleServiceFactory"),
1631 static_cast< cppu::OWeakObject * >(this), 0);
1634 css::uno::Reference< css::lang::XComponent > comp(
1635 factoryInfo, css::uno::UNO_QUERY);
1636 boost::shared_ptr< Data::Implementation > impl(
1637 new Data::Implementation(name, f1, f2, comp));
1638 Data extra;
1639 if (!name.isEmpty()) {
1640 extra.namedImplementations.insert(
1641 Data::NamedImplementations::value_type(name, impl));
1643 extra.dynamicImplementations.insert(
1644 Data::DynamicImplementations::value_type(factoryInfo, impl));
1645 css::uno::Sequence< rtl::OUString > services(
1646 factoryInfo->getSupportedServiceNames());
1647 for (sal_Int32 i = 0; i != services.getLength(); ++i) {
1648 impl->info->services.push_back(services[i]);
1649 extra.services[services[i]].push_back(impl);
1651 if (insertExtraData(extra) && comp.is()) {
1652 comp->addEventListener(this);
1656 bool cppuhelper::ServiceManager::insertExtraData(Data const & extra) {
1658 osl::MutexGuard g(rBHelper.rMutex);
1659 if (isDisposed()) {
1660 return false;
1662 for (Data::NamedImplementations::const_iterator i(
1663 extra.namedImplementations.begin());
1664 i != extra.namedImplementations.end(); ++i)
1666 if (data_.namedImplementations.find(i->first)
1667 != data_.namedImplementations.end())
1669 throw css::lang::IllegalArgumentException(
1670 "Insert duplicate implementation name " + i->first,
1671 static_cast< cppu::OWeakObject * >(this), 0);
1674 for (Data::DynamicImplementations::const_iterator i(
1675 extra.dynamicImplementations.begin());
1676 i != extra.dynamicImplementations.end(); ++i)
1678 if (data_.dynamicImplementations.find(i->first)
1679 != data_.dynamicImplementations.end())
1681 throw css::lang::IllegalArgumentException(
1682 "Insert duplicate factory object",
1683 static_cast< cppu::OWeakObject * >(this), 0);
1686 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1687 data_.namedImplementations.insert(
1688 extra.namedImplementations.begin(),
1689 extra.namedImplementations.end());
1690 data_.dynamicImplementations.insert(
1691 extra.dynamicImplementations.begin(),
1692 extra.dynamicImplementations.end());
1693 insertImplementationMap(&data_.services, extra.services);
1694 insertImplementationMap(&data_.singletons, extra.singletons);
1696 //TODO: Updating the component context singleton data should be part of the
1697 // atomic service manager update:
1698 if (!extra.singletons.empty()) {
1699 assert(context_.is());
1700 css::uno::Reference< css::container::XNameContainer > cont(
1701 context_, css::uno::UNO_QUERY_THROW);
1702 for (Data::ImplementationMap::const_iterator i(
1703 extra.singletons.begin());
1704 i != extra.singletons.end(); ++i)
1706 rtl::OUString name("/singletons/" + i->first);
1707 //TODO: Update should be atomic:
1708 try {
1709 cont->removeByName(name + "/arguments");
1710 } catch (const css::container::NoSuchElementException &) {}
1711 assert(!i->second.empty());
1712 assert(i->second[0].get() != 0);
1713 SAL_INFO_IF(
1714 i->second.size() > 1, "cppuhelper",
1715 "Arbitrarily chosing " << i->second[0]->info->name
1716 << " among multiple implementations for singleton "
1717 << i->first);
1718 try {
1719 cont->insertByName(
1720 name + "/service", css::uno::Any(i->second[0]->info->name));
1721 } catch (css::container::ElementExistException &) {
1722 cont->replaceByName(
1723 name + "/service", css::uno::Any(i->second[0]->info->name));
1725 try {
1726 cont->insertByName(name, css::uno::Any());
1727 } catch (css::container::ElementExistException &) {
1728 SAL_INFO("cppuhelper", "Overwriting singleton " << i->first);
1729 cont->replaceByName(name, css::uno::Any());
1733 return true;
1736 void cppuhelper::ServiceManager::removeRdbFiles(
1737 std::vector< rtl::OUString > const & uris)
1739 // The underlying data structures make this function somewhat inefficient,
1740 // but the assumption is that it is rarely called (and that if it is called,
1741 // it is called with a uris vector of size one):
1742 std::vector< boost::shared_ptr< Data::Implementation > > clear;
1744 osl::MutexGuard g(rBHelper.rMutex);
1745 for (std::vector< rtl::OUString >::const_iterator i(uris.begin());
1746 i != uris.end(); ++i)
1748 for (Data::NamedImplementations::iterator j(
1749 data_.namedImplementations.begin());
1750 j != data_.namedImplementations.end();)
1752 assert(j->second.get() != 0);
1753 if (j->second->info->rdbFile == *i) {
1754 clear.push_back(j->second);
1755 //TODO: The below leaves data_ in an inconsistent state upon
1756 // exceptions:
1757 removeFromImplementationMap(
1758 &data_.services, j->second->info->services, j->second);
1759 removeFromImplementationMap(
1760 &data_.singletons, j->second->info->singletons,
1761 j->second);
1762 data_.namedImplementations.erase(j++);
1763 } else {
1764 ++j;
1769 //TODO: Update the component context singleton data
1772 bool cppuhelper::ServiceManager::removeLegacyFactory(
1773 css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo,
1774 bool removeListener)
1776 assert(factoryInfo.is());
1777 boost::shared_ptr< Data::Implementation > clear;
1778 css::uno::Reference< css::lang::XComponent > comp;
1780 osl::MutexGuard g(rBHelper.rMutex);
1781 Data::DynamicImplementations::iterator i(
1782 data_.dynamicImplementations.find(factoryInfo));
1783 if (i == data_.dynamicImplementations.end()) {
1784 return isDisposed();
1786 assert(i->second.get() != 0);
1787 clear = i->second;
1788 if (removeListener) {
1789 comp = i->second->component;
1791 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1792 removeFromImplementationMap(
1793 &data_.services, i->second->info->services, i->second);
1794 removeFromImplementationMap(
1795 &data_.singletons, i->second->info->singletons, i->second);
1796 if (!i->second->info->name.isEmpty()) {
1797 data_.namedImplementations.erase(i->second->info->name);
1799 data_.dynamicImplementations.erase(i);
1801 if (comp.is()) {
1802 removeEventListenerFromComponent(comp);
1804 return true;
1807 void cppuhelper::ServiceManager::removeImplementation(const rtl::OUString & name) {
1808 // The underlying data structures make this function somewhat inefficient,
1809 // but the assumption is that it is rarely called:
1810 boost::shared_ptr< Data::Implementation > clear;
1812 osl::MutexGuard g(rBHelper.rMutex);
1813 if (isDisposed()) {
1814 return;
1816 Data::NamedImplementations::iterator i(
1817 data_.namedImplementations.find(name));
1818 if (i == data_.namedImplementations.end()) {
1819 throw css::container::NoSuchElementException(
1820 "Remove non-inserted implementation " + name,
1821 static_cast< cppu::OWeakObject * >(this));
1823 assert(i->second.get() != 0);
1824 clear = i->second;
1825 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1826 removeFromImplementationMap(
1827 &data_.services, i->second->info->services, i->second);
1828 removeFromImplementationMap(
1829 &data_.singletons, i->second->info->singletons, i->second);
1830 for (Data::DynamicImplementations::iterator j(
1831 data_.dynamicImplementations.begin());
1832 j != data_.dynamicImplementations.end(); ++j)
1834 if (j->second == i->second) {
1835 data_.dynamicImplementations.erase(j);
1836 break;
1839 data_.namedImplementations.erase(i);
1843 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
1844 cppuhelper::ServiceManager::findServiceImplementation(
1845 css::uno::Reference< css::uno::XComponentContext > const & context,
1846 rtl::OUString const & specifier)
1848 boost::shared_ptr< Data::Implementation > impl;
1849 bool loaded;
1851 osl::MutexGuard g(rBHelper.rMutex);
1852 Data::ImplementationMap::const_iterator i(
1853 data_.services.find(specifier));
1854 if (i == data_.services.end()) {
1855 Data::NamedImplementations::const_iterator j(
1856 data_.namedImplementations.find(specifier));
1857 if (j == data_.namedImplementations.end()) {
1858 SAL_INFO("cppuhelper", "No implementation for " << specifier);
1859 return boost::shared_ptr< Data::Implementation >();
1861 impl = j->second;
1862 } else {
1863 assert(!i->second.empty());
1864 SAL_INFO_IF(
1865 i->second.size() > 1, "cppuhelper",
1866 "Arbitrarily chosing " << i->second[0]->info->name
1867 << " among multiple implementations for " << i->first);
1868 impl = i->second[0];
1870 assert(impl.get() != 0);
1871 loaded = impl->status == Data::Implementation::STATUS_LOADED;
1873 if (!loaded) {
1874 loadImplementation(context, impl);
1876 return impl;
1879 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */