Bump version to 4.3-4
[LibreOffice.git] / cppuhelper / source / servicemanager.cxx
blob20471b704cc77d5c7a22b5161688d3eea9f15512
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 "com/sun/star/beans/NamedValue.hpp"
19 #include "com/sun/star/beans/PropertyAttribute.hpp"
20 #include "com/sun/star/container/ElementExistException.hpp"
21 #include "com/sun/star/container/XEnumeration.hpp"
22 #include "com/sun/star/container/XNameContainer.hpp"
23 #include "com/sun/star/lang/XInitialization.hpp"
24 #include "com/sun/star/lang/XServiceInfo.hpp"
25 #include "com/sun/star/lang/XSingleComponentFactory.hpp"
26 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
27 #include "com/sun/star/loader/XImplementationLoader.hpp"
28 #include "com/sun/star/registry/InvalidRegistryException.hpp"
29 #include "com/sun/star/uno/DeploymentException.hpp"
30 #include "com/sun/star/uno/Reference.hxx"
31 #include "com/sun/star/uno/XComponentContext.hpp"
32 #include "cppuhelper/bootstrap.hxx"
33 #include "cppuhelper/component_context.hxx"
34 #include "cppuhelper/implbase1.hxx"
35 #include "cppuhelper/implbase3.hxx"
36 #include "cppuhelper/shlib.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 css::uno::Reference< css::uno::XInterface >());
166 case STATE_END:
167 if (res == xmlreader::XmlReader::RESULT_DONE) {
168 return;
170 throw css::registry::InvalidRegistryException(
171 reader_.getUrl() + ": unexpected item in outer level",
172 css::uno::Reference< css::uno::XInterface >());
173 case STATE_COMPONENTS:
174 if (res == xmlreader::XmlReader::RESULT_END) {
175 state = STATE_END;
176 break;
178 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
179 && name.equals(RTL_CONSTASCII_STRINGPARAM("component")))
181 handleComponent();
182 state = STATE_COMPONENT_INITIAL;
183 break;
185 throw css::registry::InvalidRegistryException(
186 reader_.getUrl() + ": unexpected item in <components>",
187 css::uno::Reference< css::uno::XInterface >());
188 case STATE_COMPONENT:
189 if (res == xmlreader::XmlReader::RESULT_END) {
190 state = STATE_COMPONENTS;
191 break;
193 // fall through
194 case STATE_COMPONENT_INITIAL:
195 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
196 && name.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
198 handleImplementation();
199 state = STATE_IMPLEMENTATION;
200 break;
202 throw css::registry::InvalidRegistryException(
203 reader_.getUrl() + ": unexpected item in <component>",
204 css::uno::Reference< css::uno::XInterface >());
205 case STATE_IMPLEMENTATION:
206 if (res == xmlreader::XmlReader::RESULT_END) {
207 state = STATE_COMPONENT;
208 break;
210 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
211 && name.equals(RTL_CONSTASCII_STRINGPARAM("service")))
213 handleService();
214 state = STATE_SERVICE;
215 break;
217 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
218 && name.equals(RTL_CONSTASCII_STRINGPARAM("singleton")))
220 handleSingleton();
221 state = STATE_SINGLETON;
222 break;
224 throw css::registry::InvalidRegistryException(
225 reader_.getUrl() + ": unexpected item in <implementation>",
226 css::uno::Reference< css::uno::XInterface >());
227 case STATE_SERVICE:
228 if (res == xmlreader::XmlReader::RESULT_END) {
229 state = STATE_IMPLEMENTATION;
230 break;
232 throw css::registry::InvalidRegistryException(
233 reader_.getUrl() + ": unexpected item in <service>",
234 css::uno::Reference< css::uno::XInterface >());
235 case STATE_SINGLETON:
236 if (res == xmlreader::XmlReader::RESULT_END) {
237 state = STATE_IMPLEMENTATION;
238 break;
240 throw css::registry::InvalidRegistryException(
241 reader_.getUrl() + ": unexpected item in <service>",
242 css::uno::Reference< css::uno::XInterface >());
247 void Parser::handleComponent() {
248 attrLoader_ = rtl::OUString();
249 attrUri_ = rtl::OUString();
250 attrEnvironment_ = rtl::OUString();
251 attrPrefix_ = rtl::OUString();
252 xmlreader::Span name;
253 int nsId;
254 while (reader_.nextAttribute(&nsId, &name)) {
255 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
256 && name.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
258 if (!attrLoader_.isEmpty()) {
259 throw css::registry::InvalidRegistryException(
260 (reader_.getUrl()
261 + ": <component> has multiple \"loader\" attributes"),
262 css::uno::Reference< css::uno::XInterface >());
264 attrLoader_ = reader_.getAttributeValue(false).convertFromUtf8();
265 if (attrLoader_.isEmpty()) {
266 throw css::registry::InvalidRegistryException(
267 (reader_.getUrl()
268 + ": <component> has empty \"loader\" attribute"),
269 css::uno::Reference< css::uno::XInterface >());
271 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
272 && name.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
274 if (!attrUri_.isEmpty()) {
275 throw css::registry::InvalidRegistryException(
276 (reader_.getUrl()
277 + ": <component> has multiple \"uri\" attributes"),
278 css::uno::Reference< css::uno::XInterface >());
280 attrUri_ = reader_.getAttributeValue(false).convertFromUtf8();
281 if (attrUri_.isEmpty()) {
282 throw css::registry::InvalidRegistryException(
283 (reader_.getUrl()
284 + ": <component> has empty \"uri\" attribute"),
285 css::uno::Reference< css::uno::XInterface >());
287 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
288 && name.equals(RTL_CONSTASCII_STRINGPARAM("environment")))
290 if (!attrEnvironment_.isEmpty()) {
291 throw css::registry::InvalidRegistryException(
292 (reader_.getUrl() +
293 ": <component> has multiple \"environment\" attributes"),
294 css::uno::Reference< css::uno::XInterface >());
296 attrEnvironment_ = reader_.getAttributeValue(false)
297 .convertFromUtf8();
298 if (attrEnvironment_.isEmpty()) {
299 throw css::registry::InvalidRegistryException(
300 (reader_.getUrl() +
301 ": <component> has empty \"environment\" attribute"),
302 css::uno::Reference< css::uno::XInterface >());
304 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
305 && name.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
307 if (!attrPrefix_.isEmpty()) {
308 throw css::registry::InvalidRegistryException(
309 (reader_.getUrl() +
310 ": <component> has multiple \"prefix\" attributes"),
311 css::uno::Reference< css::uno::XInterface >());
313 attrPrefix_ = reader_.getAttributeValue(false).convertFromUtf8();
314 if (attrPrefix_.isEmpty()) {
315 throw css::registry::InvalidRegistryException(
316 (reader_.getUrl() +
317 ": <component> has empty \"prefix\" attribute"),
318 css::uno::Reference< css::uno::XInterface >());
320 } else {
321 throw css::registry::InvalidRegistryException(
322 (reader_.getUrl() + ": unexpected attribute \""
323 + name.convertFromUtf8() + "\" in <component>"),
324 css::uno::Reference< css::uno::XInterface >());
327 if (attrLoader_.isEmpty()) {
328 throw css::registry::InvalidRegistryException(
329 reader_.getUrl() + ": <component> is missing \"loader\" attribute",
330 css::uno::Reference< css::uno::XInterface >());
332 if (attrUri_.isEmpty()) {
333 throw css::registry::InvalidRegistryException(
334 reader_.getUrl() + ": <component> is missing \"uri\" attribute",
335 css::uno::Reference< css::uno::XInterface >());
337 #ifndef DISABLE_DYNLOADING
338 try {
339 attrUri_ = rtl::Uri::convertRelToAbs(reader_.getUrl(), attrUri_);
340 } catch (const rtl::MalformedUriException & e) {
341 throw css::registry::InvalidRegistryException(
342 reader_.getUrl() + ": bad \"uri\" attribute: " + e.getMessage(),
343 css::uno::Reference< css::uno::XInterface >());
345 #endif
348 void Parser::handleImplementation() {
349 rtl::OUString attrName;
350 rtl::OUString attrConstructor;
351 xmlreader::Span name;
352 int nsId;
353 while (reader_.nextAttribute(&nsId, &name)) {
354 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
355 && name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
357 if (!attrName.isEmpty()) {
358 throw css::registry::InvalidRegistryException(
359 (reader_.getUrl()
360 + ": <implementation> has multiple \"name\" attributes"),
361 css::uno::Reference< css::uno::XInterface >());
363 attrName = reader_.getAttributeValue(false).convertFromUtf8();
364 if (attrName.isEmpty()) {
365 throw css::registry::InvalidRegistryException(
366 (reader_.getUrl()
367 + ": <implementation> has empty \"name\" attribute"),
368 css::uno::Reference< css::uno::XInterface >());
370 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
371 && name.equals(RTL_CONSTASCII_STRINGPARAM("constructor")))
373 if (!attrConstructor.isEmpty()) {
374 throw css::registry::InvalidRegistryException(
375 (reader_.getUrl()
376 + (": <implementation> has multiple \"constructor\""
377 " attributes")),
378 css::uno::Reference< css::uno::XInterface >());
380 attrConstructor = reader_.getAttributeValue(false)
381 .convertFromUtf8();
382 if (attrConstructor.isEmpty()) {
383 throw css::registry::InvalidRegistryException(
384 (reader_.getUrl()
385 + ": element has empty \"constructor\" attribute"),
386 css::uno::Reference< css::uno::XInterface >());
388 if (attrEnvironment_.isEmpty()) {
389 throw css::registry::InvalidRegistryException(
390 (reader_.getUrl()
391 + (": <implementation> has \"constructor\" attribute but"
392 " <component> has no \"environment\" attribute")),
393 css::uno::Reference< css::uno::XInterface >());
395 } else {
396 throw css::registry::InvalidRegistryException(
397 (reader_.getUrl() + ": unexpected element attribute \""
398 + name.convertFromUtf8() + "\" in <implementation>"),
399 css::uno::Reference< css::uno::XInterface >());
402 if (attrName.isEmpty()) {
403 throw css::registry::InvalidRegistryException(
404 (reader_.getUrl()
405 + ": <implementation> is missing \"name\" attribute"),
406 css::uno::Reference< css::uno::XInterface >());
408 implementation_.reset(
409 new cppuhelper::ServiceManager::Data::Implementation(
410 attrName, attrLoader_, attrUri_, attrEnvironment_, attrConstructor,
411 attrPrefix_, alienContext_, reader_.getUrl()));
412 if (!data_->namedImplementations.insert(
413 cppuhelper::ServiceManager::Data::NamedImplementations::value_type(
414 attrName, implementation_)).
415 second)
417 throw css::registry::InvalidRegistryException(
418 (reader_.getUrl() + ": duplicate <implementation name=\"" + attrName
419 + "\">"),
420 css::uno::Reference< css::uno::XInterface >());
424 void Parser::handleService() {
425 rtl::OUString name(getNameAttribute());
426 implementation_->info->services.push_back(name);
427 data_->services[name].push_back(implementation_);
430 void Parser::handleSingleton() {
431 rtl::OUString name(getNameAttribute());
432 implementation_->info->singletons.push_back(name);
433 data_->singletons[name].push_back(implementation_);
436 rtl::OUString Parser::getNameAttribute() {
437 rtl::OUString attrName;
438 xmlreader::Span name;
439 int nsId;
440 while (reader_.nextAttribute(&nsId, &name)) {
441 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
442 && name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
444 if (!attrName.isEmpty()) {
445 throw css::registry::InvalidRegistryException(
446 (reader_.getUrl()
447 + ": element has multiple \"name\" attributes"),
448 css::uno::Reference< css::uno::XInterface >());
450 attrName = reader_.getAttributeValue(false).convertFromUtf8();
451 if (attrName.isEmpty()) {
452 throw css::registry::InvalidRegistryException(
453 reader_.getUrl() + ": element has empty \"name\" attribute",
454 css::uno::Reference< css::uno::XInterface >());
456 } else {
457 throw css::registry::InvalidRegistryException(
458 reader_.getUrl() + ": expected element attribute \"name\"",
459 css::uno::Reference< css::uno::XInterface >());
462 if (attrName.isEmpty()) {
463 throw css::registry::InvalidRegistryException(
464 reader_.getUrl() + ": element is missing \"name\" attribute",
465 css::uno::Reference< css::uno::XInterface >());
467 return attrName;
470 class ContentEnumeration:
471 public cppu::WeakImplHelper1< css::container::XEnumeration >,
472 private boost::noncopyable
474 public:
475 explicit ContentEnumeration(std::vector< css::uno::Any > const & factories):
476 factories_(factories), iterator_(factories_.begin()) {}
478 private:
479 virtual ~ContentEnumeration() {}
481 virtual sal_Bool SAL_CALL hasMoreElements()
482 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
484 virtual css::uno::Any SAL_CALL nextElement()
485 throw (
486 css::container::NoSuchElementException,
487 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
489 osl::Mutex mutex_;
490 std::vector< css::uno::Any > factories_;
491 std::vector< css::uno::Any >::const_iterator iterator_;
494 sal_Bool ContentEnumeration::hasMoreElements()
495 throw (css::uno::RuntimeException, std::exception)
497 osl::MutexGuard g(mutex_);
498 return iterator_ != factories_.end();
501 css::uno::Any ContentEnumeration::nextElement()
502 throw (
503 css::container::NoSuchElementException,
504 css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception)
506 osl::MutexGuard g(mutex_);
507 if (iterator_ == factories_.end()) {
508 throw css::container::NoSuchElementException(
509 "Bootstrap service manager service enumerator has no more elements",
510 static_cast< cppu::OWeakObject * >(this));
512 return *iterator_++;
515 css::beans::Property getDefaultContextProperty() {
516 return css::beans::Property(
517 "DefaultContext", -1,
518 cppu::UnoType< css::uno::XComponentContext >::get(),
519 css::beans::PropertyAttribute::READONLY);
522 class SingletonFactory:
523 public cppu::WeakImplHelper1<css::lang::XSingleComponentFactory>,
524 private boost::noncopyable
526 public:
527 SingletonFactory(
528 rtl::Reference< cppuhelper::ServiceManager > const & manager,
529 boost::shared_ptr<
530 cppuhelper::ServiceManager::Data::Implementation > const &
531 implementation):
532 manager_(manager), implementation_(implementation)
533 { assert(manager.is()); assert(implementation.get() != 0); }
535 private:
536 virtual ~SingletonFactory() {}
538 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
539 createInstanceWithContext(
540 css::uno::Reference< css::uno::XComponentContext > const & Context)
541 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
543 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
544 createInstanceWithArgumentsAndContext(
545 css::uno::Sequence< css::uno::Any > const & Arguments,
546 css::uno::Reference< css::uno::XComponentContext > const & Context)
547 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
549 rtl::Reference< cppuhelper::ServiceManager > manager_;
550 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
551 implementation_;
554 css::uno::Reference< css::uno::XInterface >
555 SingletonFactory::createInstanceWithContext(
556 css::uno::Reference< css::uno::XComponentContext > const & Context)
557 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
559 manager_->loadImplementation(Context, implementation_);
560 return implementation_->createInstance(Context, true);
563 css::uno::Reference< css::uno::XInterface >
564 SingletonFactory::createInstanceWithArgumentsAndContext(
565 css::uno::Sequence< css::uno::Any > const & Arguments,
566 css::uno::Reference< css::uno::XComponentContext > const & Context)
567 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
569 manager_->loadImplementation(Context, implementation_);
570 return implementation_->createInstanceWithArguments(
571 Context, true, Arguments);
574 class ImplementationWrapper:
575 public cppu::WeakImplHelper3<
576 css::lang::XSingleComponentFactory, css::lang::XSingleServiceFactory,
577 css::lang::XServiceInfo >,
578 private boost::noncopyable
580 public:
581 ImplementationWrapper(
582 rtl::Reference< cppuhelper::ServiceManager > const & manager,
583 boost::shared_ptr<
584 cppuhelper::ServiceManager::Data::Implementation > const &
585 implementation):
586 manager_(manager), implementation_(implementation)
587 { assert(manager.is()); assert(implementation.get() != 0); }
589 private:
590 virtual ~ImplementationWrapper() {}
592 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
593 createInstanceWithContext(
594 css::uno::Reference< css::uno::XComponentContext > const & Context)
595 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
597 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
598 createInstanceWithArgumentsAndContext(
599 css::uno::Sequence< css::uno::Any > const & Arguments,
600 css::uno::Reference< css::uno::XComponentContext > const & Context)
601 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
603 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
604 createInstance() throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
606 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
607 createInstanceWithArguments(
608 css::uno::Sequence< css::uno::Any > const & Arguments)
609 throw (css::uno::Exception, css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
611 virtual rtl::OUString SAL_CALL getImplementationName()
612 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
614 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName)
615 throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
617 virtual css::uno::Sequence< rtl::OUString > SAL_CALL
618 getSupportedServiceNames() throw (css::uno::RuntimeException, std::exception) SAL_OVERRIDE;
620 rtl::Reference< cppuhelper::ServiceManager > manager_;
621 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
622 implementation_;
625 css::uno::Reference< css::uno::XInterface >
626 ImplementationWrapper::createInstanceWithContext(
627 css::uno::Reference< css::uno::XComponentContext > const & Context)
628 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
630 manager_->loadImplementation(Context, implementation_);
631 return implementation_->createInstance(Context, false);
634 css::uno::Reference< css::uno::XInterface >
635 ImplementationWrapper::createInstanceWithArgumentsAndContext(
636 css::uno::Sequence< css::uno::Any > const & Arguments,
637 css::uno::Reference< css::uno::XComponentContext > const & Context)
638 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
640 manager_->loadImplementation(Context, implementation_);
641 return implementation_->createInstanceWithArguments(
642 Context, false, Arguments);
645 css::uno::Reference< css::uno::XInterface >
646 ImplementationWrapper::createInstance()
647 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
649 return createInstanceWithContext(manager_->getContext());
652 css::uno::Reference< css::uno::XInterface >
653 ImplementationWrapper::createInstanceWithArguments(
654 css::uno::Sequence< css::uno::Any > const & Arguments)
655 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
657 return createInstanceWithArgumentsAndContext(
658 Arguments, manager_->getContext());
661 rtl::OUString ImplementationWrapper::getImplementationName()
662 throw (css::uno::RuntimeException, std::exception)
664 return implementation_->info->name;
667 sal_Bool ImplementationWrapper::supportsService(rtl::OUString const & ServiceName)
668 throw (css::uno::RuntimeException, std::exception)
670 return cppu::supportsService(this, ServiceName);
673 css::uno::Sequence< rtl::OUString >
674 ImplementationWrapper::getSupportedServiceNames()
675 throw (css::uno::RuntimeException, std::exception)
677 if (implementation_->info->services.size()
678 > static_cast< sal_uInt32 >(SAL_MAX_INT32))
680 throw css::uno::RuntimeException(
681 ("Implementation " + implementation_->info->name
682 + " supports too many services"),
683 static_cast< cppu::OWeakObject * >(this));
685 css::uno::Sequence< rtl::OUString > names(
686 static_cast< sal_Int32 >(implementation_->info->services.size()));
687 sal_Int32 i = 0;
688 for (std::vector< rtl::OUString >::const_iterator j(
689 implementation_->info->services.begin());
690 j != implementation_->info->services.end(); ++j)
692 names[i++] = *j;
694 return names;
699 css::uno::Reference<css::uno::XInterface>
700 cppuhelper::ServiceManager::Data::Implementation::createInstance(
701 css::uno::Reference<css::uno::XComponentContext> const & context,
702 bool singletonRequest)
704 css::uno::Reference<css::uno::XInterface> inst;
705 if (constructor != 0) {
706 inst.set(
707 (*constructor)(context.get(), css::uno::Sequence<css::uno::Any>()),
708 SAL_NO_ACQUIRE);
709 } else if (factory1.is()) {
710 inst = factory1->createInstanceWithContext(context);
711 } else {
712 assert(factory2.is());
713 inst = factory2->createInstance();
715 updateDisposeSingleton(singletonRequest, inst);
716 return inst;
719 css::uno::Reference<css::uno::XInterface>
720 cppuhelper::ServiceManager::Data::Implementation::createInstanceWithArguments(
721 css::uno::Reference<css::uno::XComponentContext> const & context,
722 bool singletonRequest, css::uno::Sequence<css::uno::Any> const & arguments)
724 css::uno::Reference<css::uno::XInterface> inst;
725 if (constructor != 0) {
726 inst.set((*constructor)(context.get(), arguments), SAL_NO_ACQUIRE);
727 //HACK: The constructor will either observe arguments and return inst
728 // that does not implement XInitialization (or null), or ignore
729 // arguments and return inst that implements XInitialization; this
730 // should be removed again once XInitialization-based implementations
731 // have become rare:
732 css::uno::Reference<css::lang::XInitialization> init(
733 inst, css::uno::UNO_QUERY);
734 if (init.is()) {
735 init->initialize(arguments);
737 } else if (factory1.is()) {
738 inst = factory1->createInstanceWithArgumentsAndContext(
739 arguments, context);
740 } else {
741 assert(factory2.is());
742 inst = factory2->createInstanceWithArguments(arguments);
744 updateDisposeSingleton(singletonRequest, inst);
745 return inst;
748 void cppuhelper::ServiceManager::Data::Implementation::updateDisposeSingleton(
749 bool singletonRequest,
750 css::uno::Reference<css::uno::XInterface> const & instance)
752 // This is an optimization, to only call dispose once (from the component
753 // context) on a singleton that is obtained both via the component context
754 // and via the service manager; however, there is a harmless race here that
755 // may cause two calls to dispose nevertheless (also, this calls dispose on
756 // at most one of the instances obtained via the service manager, in case
757 // the implementation hands out different instances):
758 if (singletonRequest) {
759 osl::MutexGuard g(mutex);
760 disposeSingleton.clear();
761 dispose = false;
762 } else if (!info->singletons.empty()) {
763 css::uno::Reference<css::lang::XComponent> comp(
764 instance, css::uno::UNO_QUERY);
765 if (comp.is()) {
766 osl::MutexGuard g(mutex);
767 if (dispose) {
768 disposeSingleton = comp;
774 void cppuhelper::ServiceManager::addSingletonContextEntries(
775 std::vector< cppu::ContextEntry_Init > * entries)
777 assert(entries != 0);
778 for (Data::ImplementationMap::const_iterator i(data_.singletons.begin());
779 i != data_.singletons.end(); ++i)
781 assert(!i->second.empty());
782 assert(i->second[0].get() != 0);
783 SAL_INFO_IF(
784 i->second.size() > 1, "cppuhelper",
785 "Arbitrarily chosing " << i->second[0]->info->name
786 << " among multiple implementations for " << i->first);
787 entries->push_back(
788 cppu::ContextEntry_Init(
789 "/singletons/" + i->first,
790 css::uno::makeAny<
791 css::uno::Reference<css::lang::XSingleComponentFactory> >(
792 new SingletonFactory(this, i->second[0])),
793 true));
797 void cppuhelper::ServiceManager::loadImplementation(
798 css::uno::Reference< css::uno::XComponentContext > const & context,
799 boost::shared_ptr< Data::Implementation > & implementation)
801 assert(implementation.get() != 0);
803 osl::MutexGuard g(rBHelper.rMutex);
804 if (implementation->status == Data::Implementation::STATUS_LOADED) {
805 return;
808 rtl::OUString uri;
809 try {
810 uri = cppu::bootstrap_expandUri(implementation->info->uri);
811 } catch (css::lang::IllegalArgumentException & e) {
812 throw css::uno::DeploymentException(
813 "Cannot expand URI" + implementation->info->uri + ": " + e.Message,
814 static_cast< cppu::OWeakObject * >(this));
816 cppuhelper::ImplementationConstructorFn * ctor = 0;
817 css::uno::Reference< css::uno::XInterface > f0;
818 // Special handling of SharedLibrary loader, with support for environment,
819 // constructor, and prefix arguments:
820 if (!implementation->info->alienContext.is()
821 && implementation->info->loader == "com.sun.star.loader.SharedLibrary")
823 cppuhelper::detail::loadSharedLibComponentFactory(
824 uri, implementation->info->environment,
825 implementation->info->prefix, implementation->info->name,
826 implementation->info->constructor, this, &ctor, &f0);
827 if (ctor != 0) {
828 assert(!implementation->info->environment.isEmpty());
829 css::uno::Environment curEnv(css::uno::Environment::getCurrent());
830 css::uno::Environment env(
831 cppuhelper::detail::getEnvironment(
832 implementation->info->environment,
833 implementation->info->name));
834 if (!(curEnv.is() && env.is())) {
835 throw css::uno::DeploymentException(
836 "cannot get environments",
837 css::uno::Reference<css::uno::XInterface>());
839 if (curEnv.get() != env.get()) {
840 std::abort();//TODO
843 } else {
844 SAL_WARN_IF(
845 !implementation->info->environment.isEmpty(), "cppuhelper",
846 "Loader " << implementation->info->loader
847 << " and non-empty environment "
848 << implementation->info->environment);
849 SAL_WARN_IF(
850 !implementation->info->prefix.isEmpty(), "cppuhelper",
851 "Loader " << implementation->info->loader
852 << " and non-empty constructor "
853 << implementation->info->constructor);
854 SAL_WARN_IF(
855 !implementation->info->prefix.isEmpty(), "cppuhelper",
856 "Loader " << implementation->info->loader
857 << " and non-empty prefix " << implementation->info->prefix);
858 css::uno::Reference< css::uno::XComponentContext > ctxt;
859 css::uno::Reference< css::lang::XMultiComponentFactory > smgr;
860 if (implementation->info->alienContext.is()) {
861 ctxt = implementation->info->alienContext;
862 smgr = css::uno::Reference< css::lang::XMultiComponentFactory >(
863 ctxt->getServiceManager(), css::uno::UNO_SET_THROW);
864 } else {
865 assert(context.is());
866 ctxt = context;
867 smgr = this;
869 css::uno::Reference< css::loader::XImplementationLoader > loader(
870 smgr->createInstanceWithContext(implementation->info->loader, ctxt),
871 css::uno::UNO_QUERY_THROW);
872 f0 = loader->activate(
873 implementation->info->name, rtl::OUString(), uri,
874 css::uno::Reference< css::registry::XRegistryKey >());
876 css::uno::Reference<css::lang::XSingleComponentFactory> f1;
877 css::uno::Reference<css::lang::XSingleServiceFactory> f2;
878 if (ctor == 0) {
879 f1.set(f0, css::uno::UNO_QUERY);
880 if (!f1.is()) {
881 f2.set(f0, css::uno::UNO_QUERY);
882 if (!f2.is()) {
883 throw css::uno::DeploymentException(
884 ("Implementation " + implementation->info->name
885 + " does not provide a constructor or factory"),
886 static_cast< cppu::OWeakObject * >(this));
890 //TODO: There is a race here, as the relevant service factory can be removed
891 // while the mutex is unlocked and loading can thus fail, as the entity from
892 // which to load can disappear once the service factory is removed.
893 osl::MutexGuard g(rBHelper.rMutex);
894 if (!(isDisposed()
895 || implementation->status == Data::Implementation::STATUS_LOADED))
897 implementation->status = Data::Implementation::STATUS_LOADED;
898 implementation->constructor = ctor;
899 implementation->factory1 = f1;
900 implementation->factory2 = f2;
904 void cppuhelper::ServiceManager::disposing() {
905 std::vector< css::uno::Reference<css::lang::XComponent> > sngls;
906 std::vector< css::uno::Reference< css::lang::XComponent > > comps;
907 Data clear;
909 osl::MutexGuard g(rBHelper.rMutex);
910 for (Data::NamedImplementations::const_iterator i(
911 data_.namedImplementations.begin());
912 i != data_.namedImplementations.end(); ++i)
914 assert(i->second.get() != 0);
915 if (!i->second->info->singletons.empty()) {
916 osl::MutexGuard g2(i->second->mutex);
917 if (i->second->disposeSingleton.is()) {
918 sngls.push_back(i->second->disposeSingleton);
922 for (Data::DynamicImplementations::const_iterator i(
923 data_.dynamicImplementations.begin());
924 i != data_.dynamicImplementations.end(); ++i)
926 assert(i->second.get() != 0);
927 if (!i->second->info->singletons.empty()) {
928 osl::MutexGuard g2(i->second->mutex);
929 if (i->second->disposeSingleton.is()) {
930 sngls.push_back(i->second->disposeSingleton);
933 if (i->second->component.is()) {
934 comps.push_back(i->second->component);
937 data_.namedImplementations.swap(clear.namedImplementations);
938 data_.dynamicImplementations.swap(clear.dynamicImplementations);
939 data_.services.swap(clear.services);
940 data_.singletons.swap(clear.singletons);
942 for (std::vector<
943 css::uno::Reference<css::lang::XComponent> >::const_iterator i(
944 sngls.begin());
945 i != sngls.end(); ++i)
947 try {
948 (*i)->dispose();
949 } catch (css::uno::RuntimeException & e) {
950 SAL_WARN(
951 "cppuhelper",
952 "Ignoring RuntimeException \"" << e.Message
953 << "\" while disposing singleton");
956 for (std::vector<
957 css::uno::Reference< css::lang::XComponent > >::const_iterator i(
958 comps.begin());
959 i != comps.end(); ++i)
961 removeEventListenerFromComponent(*i);
965 rtl::OUString cppuhelper::ServiceManager::getImplementationName()
966 throw (css::uno::RuntimeException, std::exception)
968 return rtl::OUString(
969 "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager");
972 sal_Bool cppuhelper::ServiceManager::supportsService(
973 rtl::OUString const & ServiceName)
974 throw (css::uno::RuntimeException, std::exception)
976 return cppu::supportsService(this, ServiceName);
979 css::uno::Sequence< rtl::OUString >
980 cppuhelper::ServiceManager::getSupportedServiceNames()
981 throw (css::uno::RuntimeException, std::exception)
983 css::uno::Sequence< rtl::OUString > names(2);
984 names[0] = "com.sun.star.lang.MultiServiceFactory";
985 names[1] = "com.sun.star.lang.ServiceManager";
986 return names;
989 css::uno::Reference< css::uno::XInterface >
990 cppuhelper::ServiceManager::createInstance(
991 rtl::OUString const & aServiceSpecifier)
992 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
994 assert(context_.is());
995 return createInstanceWithContext(aServiceSpecifier, context_);
998 css::uno::Reference< css::uno::XInterface >
999 cppuhelper::ServiceManager::createInstanceWithArguments(
1000 rtl::OUString const & ServiceSpecifier,
1001 css::uno::Sequence< css::uno::Any > const & Arguments)
1002 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
1004 assert(context_.is());
1005 return createInstanceWithArgumentsAndContext(
1006 ServiceSpecifier, Arguments, context_);
1009 css::uno::Sequence< rtl::OUString >
1010 cppuhelper::ServiceManager::getAvailableServiceNames()
1011 throw (css::uno::RuntimeException, std::exception)
1013 osl::MutexGuard g(rBHelper.rMutex);
1014 if (isDisposed()) {
1015 return css::uno::Sequence< rtl::OUString >();
1017 Data::ImplementationMap::size_type n = data_.services.size();
1018 if (n > static_cast< sal_uInt32 >(SAL_MAX_INT32)) {
1019 throw css::uno::RuntimeException(
1020 "getAvailableServiceNames: too many services",
1021 static_cast< cppu::OWeakObject * >(this));
1023 css::uno::Sequence< rtl::OUString > names(static_cast< sal_Int32 >(n));
1024 sal_Int32 i = 0;
1025 for (Data::ImplementationMap::const_iterator j(data_.services.begin());
1026 j != data_.services.end(); ++j)
1028 names[i++] = j->first;
1030 assert(i == names.getLength());
1031 return names;
1034 css::uno::Reference< css::uno::XInterface >
1035 cppuhelper::ServiceManager::createInstanceWithContext(
1036 rtl::OUString const & aServiceSpecifier,
1037 css::uno::Reference< css::uno::XComponentContext > const & Context)
1038 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
1040 boost::shared_ptr< Data::Implementation > impl(
1041 findServiceImplementation(Context, aServiceSpecifier));
1042 return impl.get() == 0
1043 ? css::uno::Reference< css::uno::XInterface >()
1044 : impl->createInstance(Context, false);
1047 css::uno::Reference< css::uno::XInterface >
1048 cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext(
1049 rtl::OUString const & ServiceSpecifier,
1050 css::uno::Sequence< css::uno::Any > const & Arguments,
1051 css::uno::Reference< css::uno::XComponentContext > const & Context)
1052 throw (css::uno::Exception, css::uno::RuntimeException, std::exception)
1054 boost::shared_ptr< Data::Implementation > impl(
1055 findServiceImplementation(Context, ServiceSpecifier));
1056 return impl.get() == 0
1057 ? css::uno::Reference< css::uno::XInterface >()
1058 : impl->createInstanceWithArguments(Context, false, Arguments);
1061 css::uno::Type cppuhelper::ServiceManager::getElementType()
1062 throw (css::uno::RuntimeException, std::exception)
1064 return css::uno::Type();
1067 sal_Bool cppuhelper::ServiceManager::hasElements()
1068 throw (css::uno::RuntimeException, std::exception)
1070 osl::MutexGuard g(rBHelper.rMutex);
1071 return
1072 !(data_.namedImplementations.empty()
1073 && data_.dynamicImplementations.empty());
1076 css::uno::Reference< css::container::XEnumeration >
1077 cppuhelper::ServiceManager::createEnumeration()
1078 throw (css::uno::RuntimeException, std::exception)
1080 throw css::uno::RuntimeException(
1081 "ServiceManager createEnumeration: method not supported",
1082 static_cast< cppu::OWeakObject * >(this));
1085 sal_Bool cppuhelper::ServiceManager::has(css::uno::Any const &)
1086 throw (css::uno::RuntimeException, std::exception)
1088 throw css::uno::RuntimeException(
1089 "ServiceManager has: method not supported",
1090 static_cast< cppu::OWeakObject * >(this));
1093 void cppuhelper::ServiceManager::insert(css::uno::Any const & aElement)
1094 throw (
1095 css::lang::IllegalArgumentException,
1096 css::container::ElementExistException, css::uno::RuntimeException, std::exception)
1098 css::uno::Sequence< css::beans::NamedValue > args;
1099 if (aElement >>= args) {
1100 std::vector< rtl::OUString > uris;
1101 css::uno::Reference< css::uno::XComponentContext > alienContext;
1102 for (sal_Int32 i = 0; i < args.getLength(); ++i) {
1103 if (args[i].Name == "uri") {
1104 rtl::OUString uri;
1105 if (!(args[i].Value >>= uri)) {
1106 throw css::lang::IllegalArgumentException(
1107 "Bad uri argument",
1108 static_cast< cppu::OWeakObject * >(this), 0);
1110 uris.push_back(uri);
1111 } else if (args[i].Name == "component-context") {
1112 if (alienContext.is()) {
1113 throw css::lang::IllegalArgumentException(
1114 "Multiple component-context arguments",
1115 static_cast< cppu::OWeakObject * >(this), 0);
1117 if (!(args[i].Value >>= alienContext) || !alienContext.is()) {
1118 throw css::lang::IllegalArgumentException(
1119 "Bad component-context argument",
1120 static_cast< cppu::OWeakObject * >(this), 0);
1122 } else {
1123 throw css::lang::IllegalArgumentException(
1124 "Bad argument " + args[i].Name,
1125 static_cast< cppu::OWeakObject * >(this), 0);
1128 insertRdbFiles(uris, alienContext);
1129 return;
1131 css::uno::Reference< css::lang::XServiceInfo > info;
1132 if ((aElement >>= info) && info.is()) {
1133 insertLegacyFactory(info);
1134 return;
1136 // At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in
1137 // module languagetool) contain an (actively registered) factory that does not
1138 // implement XServiceInfo (see <http://sourceforge.net/tracker/?
1139 // func=detail&aid=3526635&group_id=110216&atid=655717> "SingletonFactory should
1140 // implement XServiceInfo"); the old OServiceManager::insert
1141 // (stoc/source/servicemanager/servicemanager.cxx) silently did not add such
1142 // broken factories to its m_ImplementationNameMap, so ignore them here for
1143 // backwards compatibility of live-insertion of extensions, too.
1145 // (The plan was that this warning would go away (and we would do the
1146 // throw instead) for the incompatible LO 4, but we changed our mind):
1147 css::uno::Reference< css::lang::XSingleComponentFactory > legacy;
1148 if ((aElement >>= legacy) && legacy.is()) {
1149 SAL_WARN(
1150 "cppuhelper",
1151 "Ignored XSingleComponentFactory not implementing XServiceInfo");
1152 return;
1155 throw css::lang::IllegalArgumentException(
1156 "Bad insert element", static_cast< cppu::OWeakObject * >(this), 0);
1159 void cppuhelper::ServiceManager::remove(css::uno::Any const & aElement)
1160 throw (
1161 css::lang::IllegalArgumentException,
1162 css::container::NoSuchElementException, css::uno::RuntimeException, std::exception)
1164 css::uno::Sequence< css::beans::NamedValue > args;
1165 if (aElement >>= args) {
1166 std::vector< rtl::OUString > uris;
1167 for (sal_Int32 i = 0; i < args.getLength(); ++i) {
1168 if (args[i].Name == "uri") {
1169 rtl::OUString uri;
1170 if (!(args[i].Value >>= uri)) {
1171 throw css::lang::IllegalArgumentException(
1172 "Bad uri argument",
1173 static_cast< cppu::OWeakObject * >(this), 0);
1175 uris.push_back(uri);
1176 } else {
1177 throw css::lang::IllegalArgumentException(
1178 "Bad argument " + args[i].Name,
1179 static_cast< cppu::OWeakObject * >(this), 0);
1182 removeRdbFiles(uris);
1183 return;
1185 css::uno::Reference< css::lang::XServiceInfo > info;
1186 if ((aElement >>= info) && info.is()) {
1187 if (!removeLegacyFactory(info, true)) {
1188 throw css::container::NoSuchElementException(
1189 "Remove non-inserted factory object",
1190 static_cast< cppu::OWeakObject * >(this));
1192 return;
1194 rtl::OUString impl;
1195 if (aElement >>= impl) {
1196 // For live-removal of extensions:
1197 removeImplementation(impl);
1198 return;
1200 throw css::lang::IllegalArgumentException(
1201 "Bad remove element", static_cast< cppu::OWeakObject * >(this), 0);
1204 css::uno::Reference< css::container::XEnumeration >
1205 cppuhelper::ServiceManager::createContentEnumeration(
1206 rtl::OUString const & aServiceName)
1207 throw (css::uno::RuntimeException, std::exception)
1209 std::vector< boost::shared_ptr< Data::Implementation > > impls;
1211 osl::MutexGuard g(rBHelper.rMutex);
1212 Data::ImplementationMap::const_iterator i(
1213 data_.services.find(aServiceName));
1214 if (i != data_.services.end()) {
1215 impls = i->second;
1218 std::vector< css::uno::Any > factories;
1219 for (std::vector<
1220 boost::shared_ptr< Data::Implementation > >::const_iterator i(
1221 impls.begin());
1222 i != impls.end(); ++i)
1224 Data::Implementation * impl = i->get();
1225 assert(impl != 0);
1227 osl::MutexGuard g(rBHelper.rMutex);
1228 if (isDisposed()) {
1229 factories.clear();
1230 break;
1232 if (impl->status == Data::Implementation::STATUS_NEW) {
1233 // Postpone actual implementation instantiation as long as
1234 // possible (so that e.g. opening LO's "Tools - Macros" menu
1235 // does not try to instantiate a JVM, which can lead to a
1236 // synchronous error dialog when no JVM is specified, and
1237 // showing the dialog while hovering over a menu can cause
1238 // trouble):
1239 impl->factory1 = new ImplementationWrapper(this, *i);
1240 impl->status = Data::Implementation::STATUS_WRAPPER;
1243 if (impl->factory1.is()) {
1244 factories.push_back(css::uno::makeAny(impl->factory1));
1245 } else if (impl->factory2.is()) {
1246 factories.push_back(css::uno::makeAny(impl->factory2));
1247 } else {
1248 css::uno::Reference< css::lang::XSingleComponentFactory > factory(
1249 new ImplementationWrapper(this, *i));
1250 factories.push_back(css::uno::makeAny(factory));
1253 return new ContentEnumeration(factories);
1256 css::uno::Reference< css::beans::XPropertySetInfo >
1257 cppuhelper::ServiceManager::getPropertySetInfo()
1258 throw (css::uno::RuntimeException, std::exception)
1260 return this;
1263 void cppuhelper::ServiceManager::setPropertyValue(
1264 rtl::OUString const & aPropertyName, css::uno::Any const &)
1265 throw (
1266 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1267 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1268 css::uno::RuntimeException, std::exception)
1270 if (aPropertyName == "DefaultContext") {
1271 throw css::beans::PropertyVetoException(
1272 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1273 } else {
1274 throw css::beans::UnknownPropertyException(
1275 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1279 css::uno::Any cppuhelper::ServiceManager::getPropertyValue(
1280 rtl::OUString const & PropertyName)
1281 throw (
1282 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1283 css::uno::RuntimeException, std::exception)
1285 if (PropertyName != "DefaultContext") {
1286 throw css::beans::UnknownPropertyException(
1287 PropertyName, static_cast< cppu::OWeakObject * >(this));
1289 assert(context_.is());
1290 return css::uno::makeAny(context_);
1293 void cppuhelper::ServiceManager::addPropertyChangeListener(
1294 rtl::OUString const & aPropertyName,
1295 css::uno::Reference< css::beans::XPropertyChangeListener > const &
1296 xListener)
1297 throw (
1298 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1299 css::uno::RuntimeException, std::exception)
1301 if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1302 throw css::beans::UnknownPropertyException(
1303 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1305 // DefaultContext does not change, so just treat it as an event listener:
1306 return addEventListener(xListener);
1309 void cppuhelper::ServiceManager::removePropertyChangeListener(
1310 rtl::OUString const & aPropertyName,
1311 css::uno::Reference< css::beans::XPropertyChangeListener > const &
1312 aListener)
1313 throw (
1314 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1315 css::uno::RuntimeException, std::exception)
1317 if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1318 throw css::beans::UnknownPropertyException(
1319 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1321 // DefaultContext does not change, so just treat it as an event listener:
1322 return removeEventListener(aListener);
1325 void cppuhelper::ServiceManager::addVetoableChangeListener(
1326 rtl::OUString const & PropertyName,
1327 css::uno::Reference< css::beans::XVetoableChangeListener > const &
1328 aListener)
1329 throw (
1330 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1331 css::uno::RuntimeException, std::exception)
1333 if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1334 throw css::beans::UnknownPropertyException(
1335 PropertyName, static_cast< cppu::OWeakObject * >(this));
1337 // DefaultContext does not change, so just treat it as an event listener:
1338 return addEventListener(aListener);
1341 void cppuhelper::ServiceManager::removeVetoableChangeListener(
1342 rtl::OUString const & PropertyName,
1343 css::uno::Reference< css::beans::XVetoableChangeListener > const &
1344 aListener)
1345 throw (
1346 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1347 css::uno::RuntimeException, std::exception)
1349 if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1350 throw css::beans::UnknownPropertyException(
1351 PropertyName, static_cast< cppu::OWeakObject * >(this));
1353 // DefaultContext does not change, so just treat it as an event listener:
1354 return removeEventListener(aListener);
1357 css::uno::Sequence< css::beans::Property >
1358 cppuhelper::ServiceManager::getProperties() throw (css::uno::RuntimeException, std::exception) {
1359 css::uno::Sequence< css::beans::Property > props(1);
1360 props[0] = getDefaultContextProperty();
1361 return props;
1364 css::beans::Property cppuhelper::ServiceManager::getPropertyByName(
1365 rtl::OUString const & aName)
1366 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException, std::exception)
1368 if (aName != "DefaultContext") {
1369 throw css::beans::UnknownPropertyException(
1370 aName, static_cast< cppu::OWeakObject * >(this));
1372 return getDefaultContextProperty();
1375 sal_Bool cppuhelper::ServiceManager::hasPropertyByName(
1376 rtl::OUString const & Name)
1377 throw (css::uno::RuntimeException, std::exception)
1379 return Name == "DefaultContext";
1382 void cppuhelper::ServiceManager::disposing(
1383 css::lang::EventObject const & Source)
1384 throw (css::uno::RuntimeException, std::exception)
1386 removeLegacyFactory(
1387 css::uno::Reference< css::lang::XServiceInfo >(
1388 Source.Source, css::uno::UNO_QUERY_THROW),
1389 false);
1392 void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1393 css::uno::Reference< css::lang::XComponent > const & component)
1395 assert(component.is());
1396 try {
1397 component->removeEventListener(this);
1398 } catch (css::uno::RuntimeException & e) {
1399 SAL_INFO(
1400 "cppuhelper",
1401 "Ignored removeEventListener RuntimeException " + e.Message);
1405 void cppuhelper::ServiceManager::readRdbs(rtl::OUString const & uris) {
1406 for (sal_Int32 i = 0; i != -1;) {
1407 rtl::OUString uri(uris.getToken(0, ' ', i));
1408 if (uri.isEmpty()) {
1409 continue;
1411 bool optional;
1412 bool directory;
1413 cppu::decodeRdbUri(&uri, &optional, &directory);
1414 if (directory) {
1415 readRdbDirectory(uri, optional);
1416 } else {
1417 readRdbFile(uri, optional);
1422 void cppuhelper::ServiceManager::readRdbDirectory(
1423 rtl::OUString const & uri, bool optional)
1425 osl::Directory dir(uri);
1426 switch (dir.open()) {
1427 case osl::FileBase::E_None:
1428 break;
1429 case osl::FileBase::E_NOENT:
1430 if (optional) {
1431 SAL_INFO("cppuhelper", "Ignored optional " << uri);
1432 return;
1434 // fall through
1435 default:
1436 throw css::uno::DeploymentException(
1437 "Cannot open directory " + uri,
1438 static_cast< cppu::OWeakObject * >(this));
1440 for (;;) {
1441 rtl::OUString url;
1442 if (!cppu::nextDirectoryItem(dir, &url)) {
1443 break;
1445 readRdbFile(url, false);
1449 void cppuhelper::ServiceManager::readRdbFile(
1450 rtl::OUString const & uri, bool optional)
1452 try {
1453 Parser(
1454 uri, css::uno::Reference< css::uno::XComponentContext >(), &data_);
1455 } catch (css::container::NoSuchElementException &) {
1456 if (!optional) {
1457 throw css::uno::DeploymentException(
1458 uri + ": no such file",
1459 static_cast< cppu::OWeakObject * >(this));
1461 SAL_INFO("cppuhelper", "Ignored optional " << uri);
1462 } catch (css::registry::InvalidRegistryException & e) {
1463 if (!readLegacyRdbFile(uri)) {
1464 throw css::uno::DeploymentException(
1465 "InvalidRegistryException: " + e.Message,
1466 static_cast< cppu::OWeakObject * >(this));
1468 } catch (css::uno::RuntimeException &) {
1469 if (!readLegacyRdbFile(uri)) {
1470 throw;
1475 bool cppuhelper::ServiceManager::readLegacyRdbFile(rtl::OUString const & uri) {
1476 Registry reg;
1477 switch (reg.open(uri, REG_READONLY)) {
1478 case REG_NO_ERROR:
1479 break;
1480 case REG_REGISTRY_NOT_EXISTS:
1481 case REG_INVALID_REGISTRY:
1483 // Ignore empty rdb files (which are at least seen by subordinate
1484 // uno processes during extension registration; Registry::open can
1485 // fail on them if mmap(2) returns EINVAL for a zero length):
1486 osl::DirectoryItem item;
1487 if (osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None) {
1488 osl::FileStatus status(osl_FileStatus_Mask_FileSize);
1489 if (item.getFileStatus(status) == osl::FileBase::E_None
1490 && status.getFileSize() == 0)
1492 return true;
1496 // fall through
1497 default:
1498 return false;
1500 RegistryKey rootKey;
1501 if (reg.openRootKey(rootKey) != REG_NO_ERROR) {
1502 throw css::uno::DeploymentException(
1503 "Failure reading legacy rdb file " + uri,
1504 static_cast< cppu::OWeakObject * >(this));
1506 RegistryKeyArray impls;
1507 switch (rootKey.openSubKeys("IMPLEMENTATIONS", impls)) {
1508 case REG_NO_ERROR:
1509 break;
1510 case REG_KEY_NOT_EXISTS:
1511 return true;
1512 default:
1513 throw css::uno::DeploymentException(
1514 "Failure reading legacy rdb file " + uri,
1515 static_cast< cppu::OWeakObject * >(this));
1517 for (sal_uInt32 i = 0; i != impls.getLength(); ++i) {
1518 RegistryKey implKey(impls.getElement(i));
1519 assert(implKey.getName().match("/IMPLEMENTATIONS/"));
1520 rtl::OUString name(
1521 implKey.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1522 boost::shared_ptr< Data::Implementation > impl(
1523 new Data::Implementation(
1524 name, readLegacyRdbString(uri, implKey, "UNO/ACTIVATOR"),
1525 readLegacyRdbString(uri, implKey, "UNO/LOCATION"), "", "", "",
1526 css::uno::Reference< css::uno::XComponentContext >(), uri));
1527 if (!data_.namedImplementations.insert(
1528 Data::NamedImplementations::value_type(name, impl)).
1529 second)
1531 throw css::registry::InvalidRegistryException(
1532 uri + ": duplicate <implementation name=\"" + name + "\">",
1533 css::uno::Reference< css::uno::XInterface >());
1535 readLegacyRdbStrings(
1536 uri, implKey, "UNO/SERVICES", &impl->info->services);
1537 for (std::vector< rtl::OUString >::const_iterator j(
1538 impl->info->services.begin());
1539 j != impl->info->services.end(); ++j)
1541 data_.services[*j].push_back(impl);
1543 readLegacyRdbStrings(
1544 uri, implKey, "UNO/SINGLETONS", &impl->info->singletons);
1545 for (std::vector< rtl::OUString >::const_iterator j(
1546 impl->info->singletons.begin());
1547 j != impl->info->singletons.end(); ++j)
1549 data_.singletons[*j].push_back(impl);
1552 return true;
1555 rtl::OUString cppuhelper::ServiceManager::readLegacyRdbString(
1556 rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path)
1558 RegistryKey subkey;
1559 RegValueType t;
1560 sal_uInt32 s(0);
1561 if (key.openKey(path, subkey) != REG_NO_ERROR
1562 || subkey.getValueInfo(rtl::OUString(), &t, &s) != REG_NO_ERROR
1563 || t != RG_VALUETYPE_STRING
1564 || s == 0 || s > static_cast< sal_uInt32 >(SAL_MAX_INT32))
1566 throw css::uno::DeploymentException(
1567 "Failure reading legacy rdb file " + uri,
1568 static_cast< cppu::OWeakObject * >(this));
1570 rtl::OUString val;
1571 std::vector< char > v(s); // assuming sal_uInt32 fits into vector::size_type
1572 if (subkey.getValue(rtl::OUString(), &v[0]) != REG_NO_ERROR
1573 || v.back() != '\0'
1574 || !rtl_convertStringToUString(
1575 &val.pData, &v[0], static_cast< sal_Int32 >(s - 1),
1576 RTL_TEXTENCODING_UTF8,
1577 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1578 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1579 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
1581 throw css::uno::DeploymentException(
1582 "Failure reading legacy rdb file " + uri,
1583 static_cast< cppu::OWeakObject * >(this));
1585 return val;
1588 void cppuhelper::ServiceManager::readLegacyRdbStrings(
1589 rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path,
1590 std::vector< rtl::OUString > * strings)
1592 assert(strings != 0);
1593 RegistryKey subkey;
1594 switch (key.openKey(path, subkey)) {
1595 case REG_NO_ERROR:
1596 break;
1597 case REG_KEY_NOT_EXISTS:
1598 return;
1599 default:
1600 throw css::uno::DeploymentException(
1601 "Failure reading legacy rdb file " + uri,
1602 static_cast< cppu::OWeakObject * >(this));
1604 rtl::OUString prefix(subkey.getName() + "/");
1605 RegistryKeyNames names;
1606 if (subkey.getKeyNames(rtl::OUString(), names) != REG_NO_ERROR) {
1607 throw css::uno::DeploymentException(
1608 "Failure reading legacy rdb file " + uri,
1609 static_cast< cppu::OWeakObject * >(this));
1611 for (sal_uInt32 i = 0; i != names.getLength(); ++i) {
1612 assert(names.getElement(i).match(prefix));
1613 strings->push_back(names.getElement(i).copy(prefix.getLength()));
1617 void cppuhelper::ServiceManager::insertRdbFiles(
1618 std::vector< rtl::OUString > const & uris,
1619 css::uno::Reference< css::uno::XComponentContext > const & alienContext)
1621 Data extra;
1622 for (std::vector< rtl::OUString >::const_iterator i(uris.begin());
1623 i != uris.end(); ++i)
1625 try {
1626 Parser(*i, alienContext, &extra);
1627 } catch (css::container::NoSuchElementException &) {
1628 throw css::lang::IllegalArgumentException(
1629 *i + ": no such file", static_cast< cppu::OWeakObject * >(this),
1631 } catch (css::registry::InvalidRegistryException & e) {
1632 throw css::lang::IllegalArgumentException(
1633 "InvalidRegistryException: " + e.Message,
1634 static_cast< cppu::OWeakObject * >(this), 0);
1637 insertExtraData(extra);
1640 void cppuhelper::ServiceManager::insertLegacyFactory(
1641 css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo)
1643 assert(factoryInfo.is());
1644 rtl::OUString name(factoryInfo->getImplementationName());
1645 css::uno::Reference< css::lang::XSingleComponentFactory > f1(
1646 factoryInfo, css::uno::UNO_QUERY);
1647 css::uno::Reference< css::lang::XSingleServiceFactory > f2;
1648 if (!f1.is()) {
1649 f2 = css::uno::Reference< css::lang::XSingleServiceFactory >(
1650 factoryInfo, css::uno::UNO_QUERY);
1651 if (!f2.is()) {
1652 throw css::lang::IllegalArgumentException(
1653 ("Bad XServiceInfo argument implements neither"
1654 " XSingleComponentFactory nor XSingleServiceFactory"),
1655 static_cast< cppu::OWeakObject * >(this), 0);
1658 css::uno::Reference< css::lang::XComponent > comp(
1659 factoryInfo, css::uno::UNO_QUERY);
1660 boost::shared_ptr< Data::Implementation > impl(
1661 new Data::Implementation(name, f1, f2, comp));
1662 Data extra;
1663 if (!name.isEmpty()) {
1664 extra.namedImplementations.insert(
1665 Data::NamedImplementations::value_type(name, impl));
1667 extra.dynamicImplementations.insert(
1668 Data::DynamicImplementations::value_type(factoryInfo, impl));
1669 css::uno::Sequence< rtl::OUString > services(
1670 factoryInfo->getSupportedServiceNames());
1671 for (sal_Int32 i = 0; i != services.getLength(); ++i) {
1672 impl->info->services.push_back(services[i]);
1673 extra.services[services[i]].push_back(impl);
1675 if (insertExtraData(extra) && comp.is()) {
1676 comp->addEventListener(this);
1680 bool cppuhelper::ServiceManager::insertExtraData(Data const & extra) {
1682 osl::MutexGuard g(rBHelper.rMutex);
1683 if (isDisposed()) {
1684 return false;
1686 for (Data::NamedImplementations::const_iterator i(
1687 extra.namedImplementations.begin());
1688 i != extra.namedImplementations.end(); ++i)
1690 if (data_.namedImplementations.find(i->first)
1691 != data_.namedImplementations.end())
1693 throw css::lang::IllegalArgumentException(
1694 "Insert duplicate implementation name " + i->first,
1695 static_cast< cppu::OWeakObject * >(this), 0);
1698 for (Data::DynamicImplementations::const_iterator i(
1699 extra.dynamicImplementations.begin());
1700 i != extra.dynamicImplementations.end(); ++i)
1702 if (data_.dynamicImplementations.find(i->first)
1703 != data_.dynamicImplementations.end())
1705 throw css::lang::IllegalArgumentException(
1706 "Insert duplicate factory object",
1707 static_cast< cppu::OWeakObject * >(this), 0);
1710 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1711 data_.namedImplementations.insert(
1712 extra.namedImplementations.begin(),
1713 extra.namedImplementations.end());
1714 data_.dynamicImplementations.insert(
1715 extra.dynamicImplementations.begin(),
1716 extra.dynamicImplementations.end());
1717 insertImplementationMap(&data_.services, extra.services);
1718 insertImplementationMap(&data_.singletons, extra.singletons);
1720 //TODO: Updating the component context singleton data should be part of the
1721 // atomic service manager update:
1722 if (!extra.singletons.empty()) {
1723 assert(context_.is());
1724 css::uno::Reference< css::container::XNameContainer > cont(
1725 context_, css::uno::UNO_QUERY_THROW);
1726 for (Data::ImplementationMap::const_iterator i(
1727 extra.singletons.begin());
1728 i != extra.singletons.end(); ++i)
1730 rtl::OUString name("/singletons/" + i->first);
1731 //TODO: Update should be atomic:
1732 try {
1733 cont->removeByName(name + "/arguments");
1734 } catch (const css::container::NoSuchElementException &) {}
1735 assert(!i->second.empty());
1736 assert(i->second[0].get() != 0);
1737 SAL_INFO_IF(
1738 i->second.size() > 1, "cppuhelper",
1739 "Arbitrarily chosing " << i->second[0]->info->name
1740 << " among multiple implementations for singleton "
1741 << i->first);
1742 try {
1743 cont->insertByName(
1744 name + "/service", css::uno::Any(i->second[0]->info->name));
1745 } catch (css::container::ElementExistException &) {
1746 cont->replaceByName(
1747 name + "/service", css::uno::Any(i->second[0]->info->name));
1749 try {
1750 cont->insertByName(name, css::uno::Any());
1751 } catch (css::container::ElementExistException &) {
1752 SAL_INFO("cppuhelper", "Overwriting singleton " << i->first);
1753 cont->replaceByName(name, css::uno::Any());
1757 return true;
1760 void cppuhelper::ServiceManager::removeRdbFiles(
1761 std::vector< rtl::OUString > const & uris)
1763 // The underlying data structures make this function somewhat inefficient,
1764 // but the assumption is that it is rarely called (and that if it is called,
1765 // it is called with a uris vector of size one):
1766 std::vector< boost::shared_ptr< Data::Implementation > > clear;
1768 osl::MutexGuard g(rBHelper.rMutex);
1769 for (std::vector< rtl::OUString >::const_iterator i(uris.begin());
1770 i != uris.end(); ++i)
1772 for (Data::NamedImplementations::iterator j(
1773 data_.namedImplementations.begin());
1774 j != data_.namedImplementations.end();)
1776 assert(j->second.get() != 0);
1777 if (j->second->info->rdbFile == *i) {
1778 clear.push_back(j->second);
1779 //TODO: The below leaves data_ in an inconsistent state upon
1780 // exceptions:
1781 removeFromImplementationMap(
1782 &data_.services, j->second->info->services, j->second);
1783 removeFromImplementationMap(
1784 &data_.singletons, j->second->info->singletons,
1785 j->second);
1786 data_.namedImplementations.erase(j++);
1787 } else {
1788 ++j;
1793 //TODO: Update the component context singleton data
1796 bool cppuhelper::ServiceManager::removeLegacyFactory(
1797 css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo,
1798 bool removeListener)
1800 assert(factoryInfo.is());
1801 boost::shared_ptr< Data::Implementation > clear;
1802 css::uno::Reference< css::lang::XComponent > comp;
1804 osl::MutexGuard g(rBHelper.rMutex);
1805 Data::DynamicImplementations::iterator i(
1806 data_.dynamicImplementations.find(factoryInfo));
1807 if (i == data_.dynamicImplementations.end()) {
1808 return isDisposed();
1810 assert(i->second.get() != 0);
1811 clear = i->second;
1812 if (removeListener) {
1813 comp = i->second->component;
1815 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1816 removeFromImplementationMap(
1817 &data_.services, i->second->info->services, i->second);
1818 removeFromImplementationMap(
1819 &data_.singletons, i->second->info->singletons, i->second);
1820 if (!i->second->info->name.isEmpty()) {
1821 data_.namedImplementations.erase(i->second->info->name);
1823 data_.dynamicImplementations.erase(i);
1825 if (comp.is()) {
1826 removeEventListenerFromComponent(comp);
1828 return true;
1831 void cppuhelper::ServiceManager::removeImplementation(const rtl::OUString & name) {
1832 // The underlying data structures make this function somewhat inefficient,
1833 // but the assumption is that it is rarely called:
1834 boost::shared_ptr< Data::Implementation > clear;
1836 osl::MutexGuard g(rBHelper.rMutex);
1837 if (isDisposed()) {
1838 return;
1840 Data::NamedImplementations::iterator i(
1841 data_.namedImplementations.find(name));
1842 if (i == data_.namedImplementations.end()) {
1843 throw css::container::NoSuchElementException(
1844 "Remove non-inserted implementation " + name,
1845 static_cast< cppu::OWeakObject * >(this));
1847 assert(i->second.get() != 0);
1848 clear = i->second;
1849 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1850 removeFromImplementationMap(
1851 &data_.services, i->second->info->services, i->second);
1852 removeFromImplementationMap(
1853 &data_.singletons, i->second->info->singletons, i->second);
1854 for (Data::DynamicImplementations::iterator j(
1855 data_.dynamicImplementations.begin());
1856 j != data_.dynamicImplementations.end(); ++j)
1858 if (j->second == i->second) {
1859 data_.dynamicImplementations.erase(j);
1860 break;
1863 data_.namedImplementations.erase(i);
1867 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
1868 cppuhelper::ServiceManager::findServiceImplementation(
1869 css::uno::Reference< css::uno::XComponentContext > const & context,
1870 rtl::OUString const & specifier)
1872 boost::shared_ptr< Data::Implementation > impl;
1873 bool loaded;
1875 osl::MutexGuard g(rBHelper.rMutex);
1876 Data::ImplementationMap::const_iterator i(
1877 data_.services.find(specifier));
1878 if (i == data_.services.end()) {
1879 Data::NamedImplementations::const_iterator j(
1880 data_.namedImplementations.find(specifier));
1881 if (j == data_.namedImplementations.end()) {
1882 SAL_INFO("cppuhelper", "No implementation for " << specifier);
1883 return boost::shared_ptr< Data::Implementation >();
1885 impl = j->second;
1886 } else {
1887 assert(!i->second.empty());
1888 SAL_INFO_IF(
1889 i->second.size() > 1, "cppuhelper",
1890 "Arbitrarily chosing " << i->second[0]->info->name
1891 << " among multiple implementations for " << i->first);
1892 impl = i->second[0];
1894 assert(impl.get() != 0);
1895 loaded = impl->status == Data::Implementation::STATUS_LOADED;
1897 if (!loaded) {
1898 loadImplementation(context, impl);
1900 return impl;
1903 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */