update credits
[LibreOffice.git] / cppuhelper / source / servicemanager.cxx
blob8affc2b8babaf0af3b4625d522cc6a7919e3a977
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/XServiceInfo.hpp"
24 #include "com/sun/star/lang/XSingleComponentFactory.hpp"
25 #include "com/sun/star/lang/XSingleServiceFactory.hpp"
26 #include "com/sun/star/loader/XImplementationLoader.hpp"
27 #include "com/sun/star/registry/InvalidRegistryException.hpp"
28 #include "com/sun/star/uno/DeploymentException.hpp"
29 #include "com/sun/star/uno/Reference.hxx"
30 #include "com/sun/star/uno/XComponentContext.hpp"
31 #include "cppuhelper/bootstrap.hxx"
32 #include "cppuhelper/component_context.hxx"
33 #include "cppuhelper/implbase1.hxx"
34 #include "cppuhelper/implbase3.hxx"
35 #include "cppuhelper/shlib.hxx"
36 #include "cppuhelper/supportsservice.hxx"
37 #include "osl/file.hxx"
38 #include "rtl/ref.hxx"
39 #include "rtl/uri.hxx"
40 #include "rtl/ustring.hxx"
41 #include "rtl/strbuf.hxx"
42 #include "sal/log.hxx"
44 using rtl::OUString;
45 using rtl::OString;
46 using rtl::OStringBuffer;
48 #include "registry/registry.hxx"
49 #include "xmlreader/xmlreader.hxx"
51 #include "paths.hxx"
52 #include "servicemanager.hxx"
54 namespace {
56 void insertImplementationMap(
57 cppuhelper::ServiceManager::Data::ImplementationMap * destination,
58 cppuhelper::ServiceManager::Data::ImplementationMap const & source)
60 assert(destination != 0);
61 for (cppuhelper::ServiceManager::Data::ImplementationMap::const_iterator i(
62 source.begin());
63 i != source.end(); ++i)
65 std::vector<
66 boost::shared_ptr<
67 cppuhelper::ServiceManager::Data::Implementation > > & impls
68 = (*destination)[i->first];
69 impls.insert(impls.end(), i->second.begin(), i->second.end());
73 void removeFromImplementationMap(
74 cppuhelper::ServiceManager::Data::ImplementationMap * map,
75 std::vector< rtl::OUString > const & elements,
76 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
77 const & implementation)
79 // The underlying data structures make this function somewhat inefficient,
80 // but the assumption is that it is rarely called:
81 assert(map != 0);
82 for (std::vector< rtl::OUString >::const_iterator i(elements.begin());
83 i != elements.end(); ++i)
85 cppuhelper::ServiceManager::Data::ImplementationMap::iterator j(
86 map->find(*i));
87 assert(j != map->end());
88 std::vector<
89 boost::shared_ptr<
90 cppuhelper::ServiceManager::Data::Implementation > >::iterator
91 k(std::find(j->second.begin(), j->second.end(), implementation));
92 assert(k != j->second.end());
93 j->second.erase(k);
94 if (j->second.empty()) {
95 map->erase(j);
100 // For simplicity, this code keeps throwing
101 // css::registry::InvalidRegistryException for invalid XML rdbs (even though
102 // that does not fit the exception's name):
103 class Parser: private boost::noncopyable {
104 public:
105 Parser(
106 rtl::OUString const & uri,
107 css::uno::Reference< css::uno::XComponentContext > const & alienContext,
108 cppuhelper::ServiceManager::Data * data);
110 private:
111 void handleComponent();
113 void handleImplementation();
115 void handleService();
117 void handleSingleton();
119 rtl::OUString getNameAttribute();
121 xmlreader::XmlReader reader_;
122 css::uno::Reference< css::uno::XComponentContext > alienContext_;
123 cppuhelper::ServiceManager::Data * data_;
124 rtl::OUString attrLoader_;
125 rtl::OUString attrUri_;
126 rtl::OUString attrPrefix_;
127 rtl::OUString attrImplementation_;
128 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
129 implementation_;
132 Parser::Parser(
133 rtl::OUString const & uri,
134 css::uno::Reference< css::uno::XComponentContext > const & alienContext,
135 cppuhelper::ServiceManager::Data * data):
136 reader_(uri), alienContext_(alienContext), data_(data)
138 assert(data != 0);
139 int ucNsId = reader_.registerNamespaceIri(
140 xmlreader::Span(
141 RTL_CONSTASCII_STRINGPARAM(
142 "http://openoffice.org/2010/uno-components")));
143 enum State {
144 STATE_BEGIN, STATE_END, STATE_COMPONENTS, STATE_COMPONENT_INITIAL,
145 STATE_COMPONENT, STATE_IMPLEMENTATION, STATE_SERVICE, STATE_SINGLETON };
146 for (State state = STATE_BEGIN;;) {
147 xmlreader::Span name;
148 int nsId;
149 xmlreader::XmlReader::Result res = reader_.nextItem(
150 xmlreader::XmlReader::TEXT_NONE, &name, &nsId);
151 switch (state) {
152 case STATE_BEGIN:
153 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
154 && name.equals(RTL_CONSTASCII_STRINGPARAM("components")))
156 state = STATE_COMPONENTS;
157 break;
159 throw css::registry::InvalidRegistryException(
160 reader_.getUrl() + ": unexpected item in outer level",
161 css::uno::Reference< css::uno::XInterface >());
162 case STATE_END:
163 if (res == xmlreader::XmlReader::RESULT_DONE) {
164 return;
166 throw css::registry::InvalidRegistryException(
167 reader_.getUrl() + ": unexpected item in outer level",
168 css::uno::Reference< css::uno::XInterface >());
169 case STATE_COMPONENTS:
170 if (res == xmlreader::XmlReader::RESULT_END) {
171 state = STATE_END;
172 break;
174 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
175 && name.equals(RTL_CONSTASCII_STRINGPARAM("component")))
177 handleComponent();
178 state = STATE_COMPONENT_INITIAL;
179 break;
181 throw css::registry::InvalidRegistryException(
182 reader_.getUrl() + ": unexpected item in <components>",
183 css::uno::Reference< css::uno::XInterface >());
184 case STATE_COMPONENT:
185 if (res == xmlreader::XmlReader::RESULT_END) {
186 state = STATE_COMPONENTS;
187 break;
189 // fall through
190 case STATE_COMPONENT_INITIAL:
191 if (res == xmlreader::XmlReader::RESULT_BEGIN && nsId == ucNsId
192 && name.equals(RTL_CONSTASCII_STRINGPARAM("implementation")))
194 handleImplementation();
195 state = STATE_IMPLEMENTATION;
196 break;
198 throw css::registry::InvalidRegistryException(
199 reader_.getUrl() + ": unexpected item in <component>",
200 css::uno::Reference< css::uno::XInterface >());
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 css::uno::Reference< css::uno::XInterface >());
223 case STATE_SERVICE:
224 if (res == xmlreader::XmlReader::RESULT_END) {
225 state = STATE_IMPLEMENTATION;
226 break;
228 throw css::registry::InvalidRegistryException(
229 reader_.getUrl() + ": unexpected item in <service>",
230 css::uno::Reference< css::uno::XInterface >());
231 case STATE_SINGLETON:
232 if (res == xmlreader::XmlReader::RESULT_END) {
233 state = STATE_IMPLEMENTATION;
234 break;
236 throw css::registry::InvalidRegistryException(
237 reader_.getUrl() + ": unexpected item in <service>",
238 css::uno::Reference< css::uno::XInterface >());
243 void Parser::handleComponent() {
244 attrLoader_ = rtl::OUString();
245 attrUri_ = rtl::OUString();
246 attrPrefix_ = rtl::OUString();
247 xmlreader::Span name;
248 int nsId;
249 while (reader_.nextAttribute(&nsId, &name)) {
250 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
251 && name.equals(RTL_CONSTASCII_STRINGPARAM("loader")))
253 if (!attrLoader_.isEmpty()) {
254 throw css::registry::InvalidRegistryException(
255 (reader_.getUrl()
256 + ": <component> has multiple \"loader\" attributes"),
257 css::uno::Reference< css::uno::XInterface >());
259 attrLoader_ = reader_.getAttributeValue(false).convertFromUtf8();
260 if (attrLoader_.isEmpty()) {
261 throw css::registry::InvalidRegistryException(
262 (reader_.getUrl()
263 + ": <component> has empty \"loader\" attribute"),
264 css::uno::Reference< css::uno::XInterface >());
266 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
267 && name.equals(RTL_CONSTASCII_STRINGPARAM("uri")))
269 if (!attrUri_.isEmpty()) {
270 throw css::registry::InvalidRegistryException(
271 (reader_.getUrl()
272 + ": <component> has multiple \"uri\" attributes"),
273 css::uno::Reference< css::uno::XInterface >());
275 attrUri_ = reader_.getAttributeValue(false).convertFromUtf8();
276 if (attrUri_.isEmpty()) {
277 throw css::registry::InvalidRegistryException(
278 (reader_.getUrl()
279 + ": <component> has empty \"uri\" attribute"),
280 css::uno::Reference< css::uno::XInterface >());
282 } else if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
283 && name.equals(RTL_CONSTASCII_STRINGPARAM("prefix")))
285 if (!attrPrefix_.isEmpty()) {
286 throw css::registry::InvalidRegistryException(
287 (reader_.getUrl() +
288 ": <component> has multiple \"prefix\" attributes"),
289 css::uno::Reference< css::uno::XInterface >());
291 attrPrefix_ = reader_.getAttributeValue(false).convertFromUtf8();
292 if (attrPrefix_.isEmpty()) {
293 throw css::registry::InvalidRegistryException(
294 (reader_.getUrl() +
295 ": <component> has empty \"prefix\" attribute"),
296 css::uno::Reference< css::uno::XInterface >());
298 } else {
299 throw css::registry::InvalidRegistryException(
300 (reader_.getUrl() + ": unexpected attribute \""
301 + name.convertFromUtf8() + "\" in <component>"),
302 css::uno::Reference< css::uno::XInterface >());
305 if (attrLoader_.isEmpty()) {
306 throw css::registry::InvalidRegistryException(
307 reader_.getUrl() + ": <component> is missing \"loader\" attribute",
308 css::uno::Reference< css::uno::XInterface >());
310 if (attrUri_.isEmpty()) {
311 throw css::registry::InvalidRegistryException(
312 reader_.getUrl() + ": <component> is missing \"uri\" attribute",
313 css::uno::Reference< css::uno::XInterface >());
315 #ifndef DISABLE_DYNLOADING
316 try {
317 attrUri_ = rtl::Uri::convertRelToAbs(reader_.getUrl(), attrUri_);
318 } catch (const rtl::MalformedUriException & e) {
319 throw css::registry::InvalidRegistryException(
320 reader_.getUrl() + ": bad \"uri\" attribute: " + e.getMessage(),
321 css::uno::Reference< css::uno::XInterface >());
323 #endif
326 void Parser::handleImplementation() {
327 attrImplementation_ = getNameAttribute();
328 implementation_.reset(
329 new cppuhelper::ServiceManager::Data::Implementation(
330 attrImplementation_, attrLoader_, attrUri_, attrPrefix_,
331 alienContext_, reader_.getUrl()));
332 if (!data_->namedImplementations.insert(
333 cppuhelper::ServiceManager::Data::NamedImplementations::value_type(
334 attrImplementation_, implementation_)).
335 second)
337 throw css::registry::InvalidRegistryException(
338 (reader_.getUrl() + ": duplicate <implementation name=\""
339 + attrImplementation_ + "\">"),
340 css::uno::Reference< css::uno::XInterface >());
344 void Parser::handleService() {
345 rtl::OUString name(getNameAttribute());
346 implementation_->info->services.push_back(name);
347 data_->services[name].push_back(implementation_);
350 void Parser::handleSingleton() {
351 rtl::OUString name(getNameAttribute());
352 implementation_->info->singletons.push_back(name);
353 data_->singletons[name].push_back(implementation_);
356 rtl::OUString Parser::getNameAttribute() {
357 rtl::OUString attrName;
358 xmlreader::Span name;
359 int nsId;
360 while (reader_.nextAttribute(&nsId, &name)) {
361 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE
362 && name.equals(RTL_CONSTASCII_STRINGPARAM("name")))
364 if (!attrName.isEmpty()) {
365 throw css::registry::InvalidRegistryException(
366 (reader_.getUrl()
367 + ": element has multiple \"name\" attributes"),
368 css::uno::Reference< css::uno::XInterface >());
370 attrName = reader_.getAttributeValue(false).convertFromUtf8();
371 if (attrName.isEmpty()) {
372 throw css::registry::InvalidRegistryException(
373 reader_.getUrl() + ": element has empty \"name\" attribute",
374 css::uno::Reference< css::uno::XInterface >());
376 } else {
377 throw css::registry::InvalidRegistryException(
378 reader_.getUrl() + ": expected element attribute \"name\"",
379 css::uno::Reference< css::uno::XInterface >());
382 if (attrName.isEmpty()) {
383 throw css::registry::InvalidRegistryException(
384 reader_.getUrl() + ": element is missing \"name\" attribute",
385 css::uno::Reference< css::uno::XInterface >());
387 return attrName;
390 class ContentEnumeration:
391 public cppu::WeakImplHelper1< css::container::XEnumeration >,
392 private boost::noncopyable
394 public:
395 explicit ContentEnumeration(std::vector< css::uno::Any > const & factories):
396 factories_(factories), iterator_(factories_.begin()) {}
398 private:
399 virtual ~ContentEnumeration() {}
401 virtual sal_Bool SAL_CALL hasMoreElements()
402 throw (css::uno::RuntimeException);
404 virtual css::uno::Any SAL_CALL nextElement()
405 throw (
406 css::container::NoSuchElementException,
407 css::lang::WrappedTargetException, css::uno::RuntimeException);
409 osl::Mutex mutex_;
410 std::vector< css::uno::Any > factories_;
411 std::vector< css::uno::Any >::const_iterator iterator_;
414 sal_Bool ContentEnumeration::hasMoreElements()
415 throw (css::uno::RuntimeException)
417 osl::MutexGuard g(mutex_);
418 return iterator_ != factories_.end();
421 css::uno::Any ContentEnumeration::nextElement()
422 throw (
423 css::container::NoSuchElementException,
424 css::lang::WrappedTargetException, css::uno::RuntimeException)
426 osl::MutexGuard g(mutex_);
427 if (iterator_ == factories_.end()) {
428 throw css::container::NoSuchElementException(
429 "Bootstrap service manager service enumerator has no more elements",
430 static_cast< cppu::OWeakObject * >(this));
432 return *iterator_++;
435 css::beans::Property getDefaultContextProperty() {
436 return css::beans::Property(
437 "DefaultContext", -1,
438 cppu::UnoType< css::uno::XComponentContext >::get(),
439 css::beans::PropertyAttribute::READONLY);
442 class FactoryWrapper:
443 public cppu::WeakImplHelper3<
444 css::lang::XSingleComponentFactory, css::lang::XSingleServiceFactory,
445 css::lang::XServiceInfo >,
446 private boost::noncopyable
448 public:
449 FactoryWrapper(
450 rtl::Reference< cppuhelper::ServiceManager > const & manager,
451 boost::shared_ptr<
452 cppuhelper::ServiceManager::Data::ImplementationInfo > const &
453 info):
454 manager_(manager), info_(info), loaded_(false)
455 { assert(manager.is() && info.get() != 0); }
457 private:
458 virtual ~FactoryWrapper() {}
460 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
461 createInstanceWithContext(
462 css::uno::Reference< css::uno::XComponentContext > const & Context)
463 throw (css::uno::Exception, css::uno::RuntimeException);
465 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
466 createInstanceWithArgumentsAndContext(
467 css::uno::Sequence< css::uno::Any > const & Arguments,
468 css::uno::Reference< css::uno::XComponentContext > const & Context)
469 throw (css::uno::Exception, css::uno::RuntimeException);
471 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
472 createInstance() throw (css::uno::Exception, css::uno::RuntimeException);
474 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
475 createInstanceWithArguments(
476 css::uno::Sequence< css::uno::Any > const & Arguments)
477 throw (css::uno::Exception, css::uno::RuntimeException);
479 virtual rtl::OUString SAL_CALL getImplementationName()
480 throw (css::uno::RuntimeException);
482 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName)
483 throw (css::uno::RuntimeException);
485 virtual css::uno::Sequence< rtl::OUString > SAL_CALL
486 getSupportedServiceNames() throw (css::uno::RuntimeException);
488 void loadImplementation(
489 css::uno::Reference< css::uno::XComponentContext > const & context);
491 rtl::Reference< cppuhelper::ServiceManager > manager_;
492 boost::shared_ptr< cppuhelper::ServiceManager::Data::ImplementationInfo >
493 info_;
495 osl::Mutex mutex_;
496 bool loaded_;
497 css::uno::Reference< css::lang::XSingleComponentFactory > factory1_;
498 css::uno::Reference< css::lang::XSingleServiceFactory > factory2_;
501 css::uno::Reference< css::uno::XInterface >
502 FactoryWrapper::createInstanceWithContext(
503 css::uno::Reference< css::uno::XComponentContext > const & Context)
504 throw (css::uno::Exception, css::uno::RuntimeException)
506 loadImplementation(Context);
507 return factory1_.is()
508 ? factory1_->createInstanceWithContext(Context)
509 : factory2_->createInstance();
512 css::uno::Reference< css::uno::XInterface >
513 FactoryWrapper::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)
518 loadImplementation(Context);
519 return factory1_.is()
520 ? factory1_->createInstanceWithArgumentsAndContext(Arguments, Context)
521 : factory2_->createInstanceWithArguments(Arguments);
524 css::uno::Reference< css::uno::XInterface > FactoryWrapper::createInstance()
525 throw (css::uno::Exception, css::uno::RuntimeException)
527 loadImplementation(manager_->getContext());
528 return factory1_.is()
529 ? factory1_->createInstanceWithContext(manager_->getContext())
530 : factory2_->createInstance();
533 css::uno::Reference< css::uno::XInterface >
534 FactoryWrapper::createInstanceWithArguments(
535 css::uno::Sequence< css::uno::Any > const & Arguments)
536 throw (css::uno::Exception, css::uno::RuntimeException)
538 loadImplementation(manager_->getContext());
539 return factory1_.is()
540 ? factory1_->createInstanceWithArgumentsAndContext(
541 Arguments, manager_->getContext())
542 : factory2_->createInstanceWithArguments(Arguments);
545 rtl::OUString FactoryWrapper::getImplementationName()
546 throw (css::uno::RuntimeException)
548 return info_->name;
551 sal_Bool FactoryWrapper::supportsService(rtl::OUString const & ServiceName)
552 throw (css::uno::RuntimeException)
554 return cppu::supportsService(this, ServiceName);
557 css::uno::Sequence< rtl::OUString > FactoryWrapper::getSupportedServiceNames()
558 throw (css::uno::RuntimeException)
560 if (info_->services.size() > static_cast< sal_uInt32 >(SAL_MAX_INT32)) {
561 throw css::uno::RuntimeException(
562 "Implementation " + info_->name + " supports too many services",
563 static_cast< cppu::OWeakObject * >(this));
565 css::uno::Sequence< rtl::OUString > names(
566 static_cast< sal_Int32 >(info_->services.size()));
567 sal_Int32 i = 0;
568 for (std::vector< rtl::OUString >::const_iterator j(
569 info_->services.begin());
570 j != info_->services.end(); ++j)
572 names[i++] = *j;
574 return names;
577 void FactoryWrapper::loadImplementation(
578 css::uno::Reference< css::uno::XComponentContext > const & context)
581 osl::MutexGuard g(mutex_);
582 if (loaded_) {
583 return;
586 css::uno::Reference< css::lang::XSingleComponentFactory > f1;
587 css::uno::Reference< css::lang::XSingleServiceFactory > f2;
588 //TODO: There is a race here, as the relevant service factory can already
589 // have been removed and loading can thus fail, as the entity from which to
590 // load can disappear once the service factory is removed:
591 manager_->loadImplementation(context, info_, &f1, &f2);
592 if (!(f1.is() || f2.is())) {
593 throw css::uno::DeploymentException(
594 "Implementation " + info_->name + " does not provide a factory",
595 static_cast< cppu::OWeakObject * >(this));
597 osl::MutexGuard g(mutex_);
598 if (!loaded_) {
599 loaded_ = true;
600 factory1_ = f1;
601 factory2_ = f2;
607 void cppuhelper::ServiceManager::addSingletonContextEntries(
608 std::vector< cppu::ContextEntry_Init > * entries) const
610 assert(entries != 0);
611 for (Data::ImplementationMap::const_iterator i(data_.singletons.begin());
612 i != data_.singletons.end(); ++i)
614 assert(!i->second.empty());
615 assert(i->second[0].get() != 0);
616 SAL_INFO_IF(
617 i->second.size() > 1, "cppuhelper",
618 "Arbitrarily chosing " << i->second[0]->info->name
619 << " among multiple implementations for " << i->first);
620 entries->push_back(
621 cppu::ContextEntry_Init(
622 "/singletons/" + i->first,
623 css::uno::makeAny(i->second[0]->info->name), true));
627 void cppuhelper::ServiceManager::loadImplementation(
628 css::uno::Reference< css::uno::XComponentContext > const & context,
629 boost::shared_ptr< Data::ImplementationInfo > const & info,
630 css::uno::Reference< css::lang::XSingleComponentFactory > * factory1,
631 css::uno::Reference< css::lang::XSingleServiceFactory > * factory2)
633 assert(
634 info.get() != 0 && factory1 != 0 && !factory1->is() && factory2 != 0
635 && !factory2->is());
636 rtl::OUString uri;
637 try {
638 uri = cppu::bootstrap_expandUri(info->uri);
639 } catch (css::lang::IllegalArgumentException & e) {
640 throw css::uno::DeploymentException(
641 "Cannot expand URI" + info->uri + ": " + e.Message,
642 static_cast< cppu::OWeakObject * >(this));
644 css::uno::Reference< css::uno::XInterface > f0;
645 // Shortcut loading via SharedLibrary loader, to pass in prefix argument
646 // (which the loader's activate implementation would normally obtain through
647 // the legacy xKey argument):
648 if (!info->alienContext.is()
649 && info->loader == "com.sun.star.loader.SharedLibrary")
651 rtl::OUString prefix(info->prefix);
652 if (!prefix.isEmpty()) {
653 prefix += "_";
655 f0 = cppu::loadSharedLibComponentFactory(
656 uri, rtl::OUString(), info->name, this,
657 css::uno::Reference< css::registry::XRegistryKey >(), prefix);
658 } else {
659 SAL_INFO_IF(
660 !info->prefix.isEmpty(), "cppuhelper",
661 "Loader " << info->loader << " and non-empty prefix "
662 << info->prefix);
663 css::uno::Reference< css::uno::XComponentContext > ctxt;
664 css::uno::Reference< css::lang::XMultiComponentFactory > smgr;
665 if (info->alienContext.is()) {
666 ctxt = info->alienContext;
667 smgr = css::uno::Reference< css::lang::XMultiComponentFactory >(
668 ctxt->getServiceManager(), css::uno::UNO_SET_THROW);
669 } else {
670 assert(context.is());
671 ctxt = context;
672 smgr = this;
674 css::uno::Reference< css::loader::XImplementationLoader > loader(
675 smgr->createInstanceWithContext(info->loader, ctxt),
676 css::uno::UNO_QUERY_THROW);
677 f0 = loader->activate(
678 info->name, rtl::OUString(), uri,
679 css::uno::Reference< css::registry::XRegistryKey >());
681 factory1->set(f0, css::uno::UNO_QUERY);
682 if (!factory1->is()) {
683 factory2->set(f0, css::uno::UNO_QUERY);
687 void cppuhelper::ServiceManager::disposing() {
688 std::vector< css::uno::Reference< css::lang::XComponent > > comps;
689 Data clear;
691 osl::MutexGuard g(rBHelper.rMutex);
692 for (Data::DynamicImplementations::const_iterator i(
693 data_.dynamicImplementations.begin());
694 i != data_.dynamicImplementations.end(); ++i)
696 assert(i->second.get() != 0);
697 if (i->second->component.is()) {
698 comps.push_back(i->second->component);
701 data_.namedImplementations.swap(clear.namedImplementations);
702 data_.dynamicImplementations.swap(clear.dynamicImplementations);
703 data_.services.swap(clear.services);
704 data_.singletons.swap(clear.singletons);
706 for (std::vector<
707 css::uno::Reference< css::lang::XComponent > >::const_iterator i(
708 comps.begin());
709 i != comps.end(); ++i)
711 removeEventListenerFromComponent(*i);
715 rtl::OUString cppuhelper::ServiceManager::getImplementationName()
716 throw (css::uno::RuntimeException)
718 return rtl::OUString(
719 "com.sun.star.comp.cppuhelper.bootstrap.ServiceManager");
722 sal_Bool cppuhelper::ServiceManager::supportsService(
723 rtl::OUString const & ServiceName)
724 throw (css::uno::RuntimeException)
726 return cppu::supportsService(this, ServiceName);
729 css::uno::Sequence< rtl::OUString >
730 cppuhelper::ServiceManager::getSupportedServiceNames()
731 throw (css::uno::RuntimeException)
733 css::uno::Sequence< rtl::OUString > names(2);
734 names[0] = "com.sun.star.lang.MultiServiceFactory";
735 names[1] = "com.sun.star.lang.ServiceManager";
736 return names;
739 css::uno::Reference< css::uno::XInterface >
740 cppuhelper::ServiceManager::createInstance(
741 rtl::OUString const & aServiceSpecifier)
742 throw (css::uno::Exception, css::uno::RuntimeException)
744 assert(context_.is());
745 return createInstanceWithContext(aServiceSpecifier, context_);
748 css::uno::Reference< css::uno::XInterface >
749 cppuhelper::ServiceManager::createInstanceWithArguments(
750 rtl::OUString const & ServiceSpecifier,
751 css::uno::Sequence< css::uno::Any > const & Arguments)
752 throw (css::uno::Exception, css::uno::RuntimeException)
754 assert(context_.is());
755 return createInstanceWithArgumentsAndContext(
756 ServiceSpecifier, Arguments, context_);
759 css::uno::Sequence< rtl::OUString >
760 cppuhelper::ServiceManager::getAvailableServiceNames()
761 throw (css::uno::RuntimeException)
763 osl::MutexGuard g(rBHelper.rMutex);
764 if (isDisposed()) {
765 return css::uno::Sequence< rtl::OUString >();
767 Data::ImplementationMap::size_type n = data_.services.size();
768 if (n > static_cast< sal_uInt32 >(SAL_MAX_INT32)) {
769 throw css::uno::RuntimeException(
770 "getAvailableServiceNames: too many services",
771 static_cast< cppu::OWeakObject * >(this));
773 css::uno::Sequence< rtl::OUString > names(static_cast< sal_Int32 >(n));
774 sal_Int32 i = 0;
775 for (Data::ImplementationMap::const_iterator j(data_.services.begin());
776 j != data_.services.end(); ++j)
778 names[i++] = j->first;
780 assert(i == names.getLength());
781 return names;
784 css::uno::Reference< css::uno::XInterface >
785 cppuhelper::ServiceManager::createInstanceWithContext(
786 rtl::OUString const & aServiceSpecifier,
787 css::uno::Reference< css::uno::XComponentContext > const & Context)
788 throw (css::uno::Exception, css::uno::RuntimeException)
790 boost::shared_ptr< Data::Implementation > impl(
791 findServiceImplementation(Context, aServiceSpecifier));
792 if (impl.get() == 0) {
793 return css::uno::Reference< css::uno::XInterface >();
795 if (impl->factory1.is()) {
796 return impl->factory1->createInstanceWithContext(Context);
798 if (impl->factory2.is()) {
799 return impl->factory2->createInstance();
801 throw css::uno::DeploymentException(
802 "Implementation " + impl->info->name + " does not provide a factory",
803 static_cast< cppu::OWeakObject * >(this));
806 css::uno::Reference< css::uno::XInterface >
807 cppuhelper::ServiceManager::createInstanceWithArgumentsAndContext(
808 rtl::OUString const & ServiceSpecifier,
809 css::uno::Sequence< css::uno::Any > const & Arguments,
810 css::uno::Reference< css::uno::XComponentContext > const & Context)
811 throw (css::uno::Exception, css::uno::RuntimeException)
813 boost::shared_ptr< Data::Implementation > impl(
814 findServiceImplementation(Context, ServiceSpecifier));
815 if (impl.get() == 0) {
816 return css::uno::Reference< css::uno::XInterface >();
818 if (impl->factory1.is()) {
819 return impl->factory1->createInstanceWithArgumentsAndContext(
820 Arguments, Context);
822 if (impl->factory2.is()) {
823 return impl->factory2->createInstanceWithArguments(Arguments);
825 throw css::uno::DeploymentException(
826 "Implementation " + impl->info->name + " does not provide a factory",
827 static_cast< cppu::OWeakObject * >(this));
830 css::uno::Type cppuhelper::ServiceManager::getElementType()
831 throw (css::uno::RuntimeException)
833 return css::uno::Type();
836 sal_Bool cppuhelper::ServiceManager::hasElements()
837 throw (css::uno::RuntimeException)
839 osl::MutexGuard g(rBHelper.rMutex);
840 return
841 !(data_.namedImplementations.empty()
842 && data_.dynamicImplementations.empty());
845 css::uno::Reference< css::container::XEnumeration >
846 cppuhelper::ServiceManager::createEnumeration()
847 throw (css::uno::RuntimeException)
849 throw css::uno::RuntimeException(
850 "ServiceManager createEnumeration: method not supported",
851 static_cast< cppu::OWeakObject * >(this));
854 sal_Bool cppuhelper::ServiceManager::has(css::uno::Any const &)
855 throw (css::uno::RuntimeException)
857 throw css::uno::RuntimeException(
858 "ServiceManager has: method not supported",
859 static_cast< cppu::OWeakObject * >(this));
862 void cppuhelper::ServiceManager::insert(css::uno::Any const & aElement)
863 throw (
864 css::lang::IllegalArgumentException,
865 css::container::ElementExistException, css::uno::RuntimeException)
867 css::uno::Sequence< css::beans::NamedValue > args;
868 if (aElement >>= args) {
869 std::vector< rtl::OUString > uris;
870 css::uno::Reference< css::uno::XComponentContext > alienContext;
871 for (sal_Int32 i = 0; i < args.getLength(); ++i) {
872 if (args[i].Name == "uri") {
873 rtl::OUString uri;
874 if (!(args[i].Value >>= uri)) {
875 throw css::lang::IllegalArgumentException(
876 "Bad uri argument",
877 static_cast< cppu::OWeakObject * >(this), 0);
879 uris.push_back(uri);
880 } else if (args[i].Name == "component-context") {
881 if (alienContext.is()) {
882 throw css::lang::IllegalArgumentException(
883 "Multiple component-context arguments",
884 static_cast< cppu::OWeakObject * >(this), 0);
886 if (!(args[i].Value >>= alienContext) || !alienContext.is()) {
887 throw css::lang::IllegalArgumentException(
888 "Bad component-context argument",
889 static_cast< cppu::OWeakObject * >(this), 0);
891 } else {
892 throw css::lang::IllegalArgumentException(
893 "Bad argument " + args[i].Name,
894 static_cast< cppu::OWeakObject * >(this), 0);
897 insertRdbFiles(uris, alienContext);
898 return;
900 css::uno::Reference< css::lang::XServiceInfo > info;
901 if ((aElement >>= info) && info.is()) {
902 insertLegacyFactory(info);
903 return;
905 // At least revisions up to 1.7 of LanguageTool.oxt (incl. the bundled 1.4.0 in
906 // module languagetool) contain an (actively registered) factory that does not
907 // implement XServiceInfo (see <http://sourceforge.net/tracker/?
908 // func=detail&aid=3526635&group_id=110216&atid=655717> "SingletonFactory should
909 // implement XServiceInfo"); the old OServiceManager::insert
910 // (stoc/source/servicemanager/servicemanager.cxx) silently did not add such
911 // broken factories to its m_ImplementationNameMap, so ignore them here for
912 // backwards compatibility of live-insertion of extensions, too.
914 // (The plan was that this warning would go away (and we would do the
915 // throw instead) for the incompatible LO 4, but we changed our mind):
916 css::uno::Reference< css::lang::XSingleComponentFactory > legacy;
917 if ((aElement >>= legacy) && legacy.is()) {
918 SAL_WARN(
919 "cppuhelper",
920 "Ignored XSingleComponentFactory not implementing XServiceInfo");
921 return;
924 throw css::lang::IllegalArgumentException(
925 "Bad insert element", static_cast< cppu::OWeakObject * >(this), 0);
928 void cppuhelper::ServiceManager::remove(css::uno::Any const & aElement)
929 throw (
930 css::lang::IllegalArgumentException,
931 css::container::NoSuchElementException, css::uno::RuntimeException)
933 css::uno::Sequence< css::beans::NamedValue > args;
934 if (aElement >>= args) {
935 std::vector< rtl::OUString > uris;
936 for (sal_Int32 i = 0; i < args.getLength(); ++i) {
937 if (args[i].Name == "uri") {
938 rtl::OUString uri;
939 if (!(args[i].Value >>= uri)) {
940 throw css::lang::IllegalArgumentException(
941 "Bad uri argument",
942 static_cast< cppu::OWeakObject * >(this), 0);
944 uris.push_back(uri);
945 } else {
946 throw css::lang::IllegalArgumentException(
947 "Bad argument " + args[i].Name,
948 static_cast< cppu::OWeakObject * >(this), 0);
951 removeRdbFiles(uris);
952 return;
954 css::uno::Reference< css::lang::XServiceInfo > info;
955 if ((aElement >>= info) && info.is()) {
956 if (!removeLegacyFactory(info, true)) {
957 throw css::container::NoSuchElementException(
958 "Remove non-inserted factory object",
959 static_cast< cppu::OWeakObject * >(this));
961 return;
963 rtl::OUString impl;
964 if (aElement >>= impl) {
965 // For live-removal of extensions:
966 removeImplementation(impl);
967 return;
969 throw css::lang::IllegalArgumentException(
970 "Bad remove element", static_cast< cppu::OWeakObject * >(this), 0);
973 css::uno::Reference< css::container::XEnumeration >
974 cppuhelper::ServiceManager::createContentEnumeration(
975 rtl::OUString const & aServiceName)
976 throw (css::uno::RuntimeException)
978 std::vector< boost::shared_ptr< Data::Implementation > > impls;
980 osl::MutexGuard g(rBHelper.rMutex);
981 Data::ImplementationMap::const_iterator i(
982 data_.services.find(aServiceName));
983 if (i != data_.services.end()) {
984 impls = i->second;
987 std::vector< css::uno::Any > factories;
988 for (std::vector<
989 boost::shared_ptr< Data::Implementation > >::const_iterator i(
990 impls.begin());
991 i != impls.end(); ++i)
993 Data::Implementation * impl = i->get();
994 assert(impl != 0);
996 osl::MutexGuard g(rBHelper.rMutex);
997 if (isDisposed()) {
998 factories.clear();
999 break;
1001 if (!impl->loaded) {
1002 // Postpone actual factory instantiation as long as possible (so
1003 // that e.g. opening LO's "Tools - Macros" menu does not try to
1004 // instantiate a JVM, which can lead to a synchronous error
1005 // dialog when no JVM is specified, and showing the dialog while
1006 // hovering over a menu can cause trouble):
1007 impl->factory1 = new FactoryWrapper(this, impl->info);
1008 impl->loaded = true;
1011 if (impl->factory1.is()) {
1012 factories.push_back(css::uno::makeAny(impl->factory1));
1013 } else if (impl->factory2.is()) {
1014 factories.push_back(css::uno::makeAny(impl->factory2));
1015 } else {
1016 throw css::uno::DeploymentException(
1017 ("Implementation " + impl->info->name
1018 + " does not provide a factory"),
1019 static_cast< cppu::OWeakObject * >(this));
1022 return new ContentEnumeration(factories);
1025 css::uno::Reference< css::beans::XPropertySetInfo >
1026 cppuhelper::ServiceManager::getPropertySetInfo()
1027 throw (css::uno::RuntimeException)
1029 return this;
1032 void cppuhelper::ServiceManager::setPropertyValue(
1033 rtl::OUString const & aPropertyName, css::uno::Any const &)
1034 throw (
1035 css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
1036 css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
1037 css::uno::RuntimeException)
1039 if (aPropertyName == "DefaultContext") {
1040 throw css::beans::PropertyVetoException(
1041 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1042 } else {
1043 throw css::beans::UnknownPropertyException(
1044 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1048 css::uno::Any cppuhelper::ServiceManager::getPropertyValue(
1049 rtl::OUString const & PropertyName)
1050 throw (
1051 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1052 css::uno::RuntimeException)
1054 if (PropertyName != "DefaultContext") {
1055 throw css::beans::UnknownPropertyException(
1056 PropertyName, static_cast< cppu::OWeakObject * >(this));
1058 assert(context_.is());
1059 return css::uno::makeAny(context_);
1062 void cppuhelper::ServiceManager::addPropertyChangeListener(
1063 rtl::OUString const & aPropertyName,
1064 css::uno::Reference< css::beans::XPropertyChangeListener > const &
1065 xListener)
1066 throw (
1067 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1068 css::uno::RuntimeException)
1070 if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1071 throw css::beans::UnknownPropertyException(
1072 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1074 // DefaultContext does not change, so just treat it as an event listener:
1075 return addEventListener(xListener.get());
1078 void cppuhelper::ServiceManager::removePropertyChangeListener(
1079 rtl::OUString const & aPropertyName,
1080 css::uno::Reference< css::beans::XPropertyChangeListener > const &
1081 aListener)
1082 throw (
1083 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1084 css::uno::RuntimeException)
1086 if (!aPropertyName.isEmpty() && aPropertyName != "DefaultContext") {
1087 throw css::beans::UnknownPropertyException(
1088 aPropertyName, static_cast< cppu::OWeakObject * >(this));
1090 // DefaultContext does not change, so just treat it as an event listener:
1091 return removeEventListener(aListener.get());
1094 void cppuhelper::ServiceManager::addVetoableChangeListener(
1095 rtl::OUString const & PropertyName,
1096 css::uno::Reference< css::beans::XVetoableChangeListener > const &
1097 aListener)
1098 throw (
1099 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1100 css::uno::RuntimeException)
1102 if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1103 throw css::beans::UnknownPropertyException(
1104 PropertyName, static_cast< cppu::OWeakObject * >(this));
1106 // DefaultContext does not change, so just treat it as an event listener:
1107 return addEventListener(aListener.get());
1110 void cppuhelper::ServiceManager::removeVetoableChangeListener(
1111 rtl::OUString const & PropertyName,
1112 css::uno::Reference< css::beans::XVetoableChangeListener > const &
1113 aListener)
1114 throw (
1115 css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
1116 css::uno::RuntimeException)
1118 if (!PropertyName.isEmpty() && PropertyName != "DefaultContext") {
1119 throw css::beans::UnknownPropertyException(
1120 PropertyName, static_cast< cppu::OWeakObject * >(this));
1122 // DefaultContext does not change, so just treat it as an event listener:
1123 return removeEventListener(aListener.get());
1126 css::uno::Sequence< css::beans::Property >
1127 cppuhelper::ServiceManager::getProperties() throw (css::uno::RuntimeException) {
1128 css::uno::Sequence< css::beans::Property > props(1);
1129 props[0] = getDefaultContextProperty();
1130 return props;
1133 css::beans::Property cppuhelper::ServiceManager::getPropertyByName(
1134 rtl::OUString const & aName)
1135 throw (css::beans::UnknownPropertyException, css::uno::RuntimeException)
1137 if (aName != "DefaultContext") {
1138 throw css::beans::UnknownPropertyException(
1139 aName, static_cast< cppu::OWeakObject * >(this));
1141 return getDefaultContextProperty();
1144 sal_Bool cppuhelper::ServiceManager::hasPropertyByName(
1145 rtl::OUString const & Name)
1146 throw (css::uno::RuntimeException)
1148 return Name == "DefaultContext";
1151 void cppuhelper::ServiceManager::disposing(
1152 css::lang::EventObject const & Source)
1153 throw (css::uno::RuntimeException)
1155 removeLegacyFactory(
1156 css::uno::Reference< css::lang::XServiceInfo >(
1157 Source.Source, css::uno::UNO_QUERY_THROW),
1158 false);
1161 void cppuhelper::ServiceManager::removeEventListenerFromComponent(
1162 css::uno::Reference< css::lang::XComponent > const & component)
1164 assert(component.is());
1165 try {
1166 component->removeEventListener(this);
1167 } catch (css::uno::RuntimeException & e) {
1168 SAL_INFO(
1169 "cppuhelper",
1170 "Ignored removeEventListener RuntimeException " + e.Message);
1174 void cppuhelper::ServiceManager::readRdbs(rtl::OUString const & uris) {
1175 for (sal_Int32 i = 0; i != -1;) {
1176 rtl::OUString uri(uris.getToken(0, ' ', i));
1177 if (uri.isEmpty()) {
1178 continue;
1180 bool optional;
1181 bool directory;
1182 cppu::decodeRdbUri(&uri, &optional, &directory);
1183 if (directory) {
1184 readRdbDirectory(uri, optional);
1185 } else {
1186 readRdbFile(uri, optional);
1191 void cppuhelper::ServiceManager::readRdbDirectory(
1192 rtl::OUString const & uri, bool optional)
1194 osl::Directory dir(uri);
1195 switch (dir.open()) {
1196 case osl::FileBase::E_None:
1197 break;
1198 case osl::FileBase::E_NOENT:
1199 if (optional) {
1200 SAL_INFO("cppuhelper", "Ignored optional " << uri);
1201 return;
1203 // fall through
1204 default:
1205 throw css::uno::DeploymentException(
1206 "Cannot open directory " + uri,
1207 static_cast< cppu::OWeakObject * >(this));
1209 for (;;) {
1210 rtl::OUString url;
1211 if (!cppu::nextDirectoryItem(dir, &url)) {
1212 break;
1214 readRdbFile(url, false);
1218 void cppuhelper::ServiceManager::readRdbFile(
1219 rtl::OUString const & uri, bool optional)
1221 try {
1222 Parser(
1223 uri, css::uno::Reference< css::uno::XComponentContext >(), &data_);
1224 } catch (css::container::NoSuchElementException &) {
1225 if (!optional) {
1226 throw css::uno::DeploymentException(
1227 uri + ": no such file",
1228 static_cast< cppu::OWeakObject * >(this));
1230 SAL_INFO("cppuhelper", "Ignored optional " << uri);
1231 } catch (css::registry::InvalidRegistryException & e) {
1232 if (!readLegacyRdbFile(uri)) {
1233 throw css::uno::DeploymentException(
1234 "InvalidRegistryException: " + e.Message,
1235 static_cast< cppu::OWeakObject * >(this));
1237 } catch (css::uno::RuntimeException &) {
1238 if (!readLegacyRdbFile(uri)) {
1239 throw;
1244 bool cppuhelper::ServiceManager::readLegacyRdbFile(rtl::OUString const & uri) {
1245 Registry reg;
1246 switch (reg.open(uri, REG_READONLY)) {
1247 case REG_NO_ERROR:
1248 break;
1249 case REG_REGISTRY_NOT_EXISTS:
1250 case REG_INVALID_REGISTRY:
1252 // Ignore empty rdb files (which are at least seen by subordinate
1253 // uno processes during extension registration; Registry::open can
1254 // fail on them if mmap(2) returns EINVAL for a zero length):
1255 osl::DirectoryItem item;
1256 if (osl::DirectoryItem::get(uri, item) == osl::FileBase::E_None) {
1257 osl::FileStatus status(osl_FileStatus_Mask_FileSize);
1258 if (item.getFileStatus(status) == osl::FileBase::E_None
1259 && status.getFileSize() == 0)
1261 return true;
1265 // fall through
1266 default:
1267 return false;
1269 RegistryKey rootKey;
1270 if (reg.openRootKey(rootKey) != REG_NO_ERROR) {
1271 throw css::uno::DeploymentException(
1272 "Failure reading legacy rdb file " + uri,
1273 static_cast< cppu::OWeakObject * >(this));
1275 RegistryKeyArray impls;
1276 switch (rootKey.openSubKeys("IMPLEMENTATIONS", impls)) {
1277 case REG_NO_ERROR:
1278 break;
1279 case REG_KEY_NOT_EXISTS:
1280 return true;
1281 default:
1282 throw css::uno::DeploymentException(
1283 "Failure reading legacy rdb file " + uri,
1284 static_cast< cppu::OWeakObject * >(this));
1286 for (sal_uInt32 i = 0; i != impls.getLength(); ++i) {
1287 RegistryKey implKey(impls.getElement(i));
1288 assert(implKey.getName().match("/IMPLEMENTATIONS/"));
1289 rtl::OUString name(
1290 implKey.getName().copy(RTL_CONSTASCII_LENGTH("/IMPLEMENTATIONS/")));
1291 boost::shared_ptr< Data::Implementation > impl(
1292 new Data::Implementation(
1293 name, readLegacyRdbString(uri, implKey, "UNO/ACTIVATOR"),
1294 readLegacyRdbString(uri, implKey, "UNO/LOCATION"),
1295 rtl::OUString(),
1296 css::uno::Reference< css::uno::XComponentContext >(), uri));
1297 if (!data_.namedImplementations.insert(
1298 Data::NamedImplementations::value_type(name, impl)).
1299 second)
1301 throw css::registry::InvalidRegistryException(
1302 uri + ": duplicate <implementation name=\"" + name + "\">",
1303 css::uno::Reference< css::uno::XInterface >());
1305 readLegacyRdbStrings(
1306 uri, implKey, "UNO/SERVICES", &impl->info->services);
1307 for (std::vector< rtl::OUString >::const_iterator j(
1308 impl->info->services.begin());
1309 j != impl->info->services.end(); ++j)
1311 data_.services[*j].push_back(impl);
1313 readLegacyRdbStrings(
1314 uri, implKey, "UNO/SINGLETONS", &impl->info->singletons);
1315 for (std::vector< rtl::OUString >::const_iterator j(
1316 impl->info->singletons.begin());
1317 j != impl->info->singletons.end(); ++j)
1319 data_.singletons[*j].push_back(impl);
1322 return true;
1325 rtl::OUString cppuhelper::ServiceManager::readLegacyRdbString(
1326 rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path)
1328 RegistryKey subkey;
1329 RegValueType t;
1330 sal_uInt32 s(0);
1331 if (key.openKey(path, subkey) != REG_NO_ERROR
1332 || subkey.getValueInfo(rtl::OUString(), &t, &s) != REG_NO_ERROR
1333 || t != RG_VALUETYPE_STRING
1334 || s == 0 || s > static_cast< sal_uInt32 >(SAL_MAX_INT32))
1336 throw css::uno::DeploymentException(
1337 "Failure reading legacy rdb file " + uri,
1338 static_cast< cppu::OWeakObject * >(this));
1340 rtl::OUString val;
1341 std::vector< char > v(s); // assuming sal_uInt32 fits into vector::size_type
1342 if (subkey.getValue(rtl::OUString(), &v[0]) != REG_NO_ERROR
1343 || v.back() != '\0'
1344 || !rtl_convertStringToUString(
1345 &val.pData, &v[0], static_cast< sal_Int32 >(s - 1),
1346 RTL_TEXTENCODING_UTF8,
1347 (RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_ERROR
1348 | RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_ERROR
1349 | RTL_TEXTTOUNICODE_FLAGS_INVALID_ERROR)))
1351 throw css::uno::DeploymentException(
1352 "Failure reading legacy rdb file " + uri,
1353 static_cast< cppu::OWeakObject * >(this));
1355 return val;
1358 void cppuhelper::ServiceManager::readLegacyRdbStrings(
1359 rtl::OUString const & uri, RegistryKey & key, rtl::OUString const & path,
1360 std::vector< rtl::OUString > * strings)
1362 assert(strings != 0);
1363 RegistryKey subkey;
1364 switch (key.openKey(path, subkey)) {
1365 case REG_NO_ERROR:
1366 break;
1367 case REG_KEY_NOT_EXISTS:
1368 return;
1369 default:
1370 throw css::uno::DeploymentException(
1371 "Failure reading legacy rdb file " + uri,
1372 static_cast< cppu::OWeakObject * >(this));
1374 rtl::OUString prefix(subkey.getName() + "/");
1375 RegistryKeyNames names;
1376 if (subkey.getKeyNames(rtl::OUString(), names) != REG_NO_ERROR) {
1377 throw css::uno::DeploymentException(
1378 "Failure reading legacy rdb file " + uri,
1379 static_cast< cppu::OWeakObject * >(this));
1381 for (sal_uInt32 i = 0; i != names.getLength(); ++i) {
1382 assert(names.getElement(i).match(prefix));
1383 strings->push_back(names.getElement(i).copy(prefix.getLength()));
1387 void cppuhelper::ServiceManager::insertRdbFiles(
1388 std::vector< rtl::OUString > const & uris,
1389 css::uno::Reference< css::uno::XComponentContext > const & alienContext)
1391 Data extra;
1392 for (std::vector< rtl::OUString >::const_iterator i(uris.begin());
1393 i != uris.end(); ++i)
1395 try {
1396 Parser(*i, alienContext, &extra);
1397 } catch (css::container::NoSuchElementException &) {
1398 throw css::lang::IllegalArgumentException(
1399 *i + ": no such file", static_cast< cppu::OWeakObject * >(this),
1401 } catch (css::registry::InvalidRegistryException & e) {
1402 throw css::lang::IllegalArgumentException(
1403 "InvalidRegistryException: " + e.Message,
1404 static_cast< cppu::OWeakObject * >(this), 0);
1407 insertExtraData(extra);
1410 void cppuhelper::ServiceManager::insertLegacyFactory(
1411 css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo)
1413 assert(factoryInfo.is());
1414 rtl::OUString name(factoryInfo->getImplementationName());
1415 css::uno::Reference< css::lang::XSingleComponentFactory > f1(
1416 factoryInfo, css::uno::UNO_QUERY);
1417 css::uno::Reference< css::lang::XSingleServiceFactory > f2;
1418 if (!f1.is()) {
1419 f2 = css::uno::Reference< css::lang::XSingleServiceFactory >(
1420 factoryInfo, css::uno::UNO_QUERY);
1422 css::uno::Reference< css::lang::XComponent > comp(
1423 factoryInfo, css::uno::UNO_QUERY);
1424 boost::shared_ptr< Data::Implementation > impl(
1425 new Data::Implementation(name, f1, f2, comp));
1426 Data extra;
1427 if (!name.isEmpty()) {
1428 extra.namedImplementations.insert(
1429 Data::NamedImplementations::value_type(name, impl));
1431 extra.dynamicImplementations.insert(
1432 Data::DynamicImplementations::value_type(factoryInfo, impl));
1433 css::uno::Sequence< rtl::OUString > services(
1434 factoryInfo->getSupportedServiceNames());
1435 for (sal_Int32 i = 0; i != services.getLength(); ++i) {
1436 impl->info->services.push_back(services[i]);
1437 extra.services[services[i]].push_back(impl);
1439 if (insertExtraData(extra) && comp.is()) {
1440 comp->addEventListener(this);
1444 bool cppuhelper::ServiceManager::insertExtraData(Data const & extra) {
1446 osl::MutexGuard g(rBHelper.rMutex);
1447 if (isDisposed()) {
1448 return false;
1450 for (Data::NamedImplementations::const_iterator i(
1451 extra.namedImplementations.begin());
1452 i != extra.namedImplementations.end(); ++i)
1454 if (data_.namedImplementations.find(i->first)
1455 != data_.namedImplementations.end())
1457 throw css::lang::IllegalArgumentException(
1458 "Insert duplicate implementation name " + i->first,
1459 static_cast< cppu::OWeakObject * >(this), 0);
1462 for (Data::DynamicImplementations::const_iterator i(
1463 extra.dynamicImplementations.begin());
1464 i != extra.dynamicImplementations.end(); ++i)
1466 if (data_.dynamicImplementations.find(i->first)
1467 != data_.dynamicImplementations.end())
1469 throw css::lang::IllegalArgumentException(
1470 "Insert duplicate factory object",
1471 static_cast< cppu::OWeakObject * >(this), 0);
1474 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1475 data_.namedImplementations.insert(
1476 extra.namedImplementations.begin(),
1477 extra.namedImplementations.end());
1478 data_.dynamicImplementations.insert(
1479 extra.dynamicImplementations.begin(),
1480 extra.dynamicImplementations.end());
1481 insertImplementationMap(&data_.services, extra.services);
1482 insertImplementationMap(&data_.singletons, extra.singletons);
1484 //TODO: Updating the component context singleton data should be part of the
1485 // atomic service manager update:
1486 if (!extra.singletons.empty()) {
1487 assert(context_.is());
1488 css::uno::Reference< css::container::XNameContainer > cont(
1489 context_, css::uno::UNO_QUERY_THROW);
1490 for (Data::ImplementationMap::const_iterator i(
1491 extra.singletons.begin());
1492 i != extra.singletons.end(); ++i)
1494 rtl::OUString name("/singletons/" + i->first);
1495 //TODO: Update should be atomic:
1496 try {
1497 cont->removeByName(name + "/arguments");
1498 } catch (const css::container::NoSuchElementException &) {}
1499 assert(!i->second.empty());
1500 assert(i->second[0].get() != 0);
1501 SAL_INFO_IF(
1502 i->second.size() > 1, "cppuhelper",
1503 "Arbitrarily chosing " << i->second[0]->info->name
1504 << " among multiple implementations for singleton "
1505 << i->first);
1506 try {
1507 cont->insertByName(
1508 name + "/service", css::uno::Any(i->second[0]->info->name));
1509 } catch (css::container::ElementExistException &) {
1510 cont->replaceByName(
1511 name + "/service", css::uno::Any(i->second[0]->info->name));
1513 try {
1514 cont->insertByName(name, css::uno::Any());
1515 } catch (css::container::ElementExistException &) {
1516 SAL_INFO("cppuhelper", "Overwriting singleton " << i->first);
1517 cont->replaceByName(name, css::uno::Any());
1521 return true;
1524 void cppuhelper::ServiceManager::removeRdbFiles(
1525 std::vector< rtl::OUString > const & uris)
1527 // The underlying data structures make this function somewhat inefficient,
1528 // but the assumption is that it is rarely called (and that if it is called,
1529 // it is called with a uris vector of size one):
1530 std::vector< boost::shared_ptr< Data::Implementation > > clear;
1532 osl::MutexGuard g(rBHelper.rMutex);
1533 for (std::vector< rtl::OUString >::const_iterator i(uris.begin());
1534 i != uris.end(); ++i)
1536 for (Data::NamedImplementations::iterator j(
1537 data_.namedImplementations.begin());
1538 j != data_.namedImplementations.end();)
1540 assert(j->second.get() != 0);
1541 if (j->second->info->rdbFile == *i) {
1542 clear.push_back(j->second);
1543 //TODO: The below leaves data_ in an inconsistent state upon
1544 // exceptions:
1545 removeFromImplementationMap(
1546 &data_.services, j->second->info->services, j->second);
1547 removeFromImplementationMap(
1548 &data_.singletons, j->second->info->singletons,
1549 j->second);
1550 data_.namedImplementations.erase(j++);
1551 } else {
1552 ++j;
1557 //TODO: Update the component context singleton data
1560 bool cppuhelper::ServiceManager::removeLegacyFactory(
1561 css::uno::Reference< css::lang::XServiceInfo > const & factoryInfo,
1562 bool removeListener)
1564 assert(factoryInfo.is());
1565 boost::shared_ptr< Data::Implementation > clear;
1566 css::uno::Reference< css::lang::XComponent > comp;
1568 osl::MutexGuard g(rBHelper.rMutex);
1569 Data::DynamicImplementations::iterator i(
1570 data_.dynamicImplementations.find(factoryInfo));
1571 if (i == data_.dynamicImplementations.end()) {
1572 return isDisposed();
1574 assert(i->second.get() != 0);
1575 clear = i->second;
1576 if (removeListener) {
1577 comp = i->second->component;
1579 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1580 removeFromImplementationMap(
1581 &data_.services, i->second->info->services, i->second);
1582 removeFromImplementationMap(
1583 &data_.singletons, i->second->info->singletons, i->second);
1584 if (!i->second->info->name.isEmpty()) {
1585 data_.namedImplementations.erase(i->second->info->name);
1587 data_.dynamicImplementations.erase(i);
1589 if (comp.is()) {
1590 removeEventListenerFromComponent(comp);
1592 return true;
1595 void cppuhelper::ServiceManager::removeImplementation(rtl::OUString name) {
1596 // The underlying data structures make this function somewhat inefficient,
1597 // but the assumption is that it is rarely called:
1598 boost::shared_ptr< Data::Implementation > clear;
1600 osl::MutexGuard g(rBHelper.rMutex);
1601 if (isDisposed()) {
1602 return;
1604 Data::NamedImplementations::iterator i(
1605 data_.namedImplementations.find(name));
1606 if (i == data_.namedImplementations.end()) {
1607 throw css::container::NoSuchElementException(
1608 "Remove non-inserted implementation " + name,
1609 static_cast< cppu::OWeakObject * >(this));
1611 assert(i->second.get() != 0);
1612 clear = i->second;
1613 //TODO: The below leaves data_ in an inconsistent state upon exceptions:
1614 removeFromImplementationMap(
1615 &data_.services, i->second->info->services, i->second);
1616 removeFromImplementationMap(
1617 &data_.singletons, i->second->info->singletons, i->second);
1618 for (Data::DynamicImplementations::iterator j(
1619 data_.dynamicImplementations.begin());
1620 j != data_.dynamicImplementations.end(); ++j)
1622 if (j->second == i->second) {
1623 data_.dynamicImplementations.erase(j);
1624 break;
1627 data_.namedImplementations.erase(i);
1631 boost::shared_ptr< cppuhelper::ServiceManager::Data::Implementation >
1632 cppuhelper::ServiceManager::findServiceImplementation(
1633 css::uno::Reference< css::uno::XComponentContext > const & context,
1634 rtl::OUString const & specifier)
1636 boost::shared_ptr< Data::Implementation > impl;
1637 bool loaded;
1639 osl::MutexGuard g(rBHelper.rMutex);
1640 Data::ImplementationMap::const_iterator i(
1641 data_.services.find(specifier));
1642 if (i == data_.services.end()) {
1643 Data::NamedImplementations::const_iterator j(
1644 data_.namedImplementations.find(specifier));
1645 if (j == data_.namedImplementations.end()) {
1646 SAL_INFO("cppuhelper", "No implementation for " << specifier);
1647 return boost::shared_ptr< Data::Implementation >();
1649 impl = j->second;
1650 } else {
1651 assert(!i->second.empty());
1652 SAL_INFO_IF(
1653 i->second.size() > 1, "cppuhelper",
1654 "Arbitrarily chosing " << i->second[0]->info->name
1655 << " among multiple implementations for " << i->first);
1656 impl = i->second[0];
1658 assert(impl.get() != 0);
1659 loaded = impl->loaded;
1661 //TODO: There is a race here, as the relevant service factory can be removed
1662 // while the mutex is unlocked and loading can thus fail, as the entity from
1663 // which to load can disappear once the service factory is removed.
1664 if (!loaded) {
1665 css::uno::Reference< css::lang::XSingleComponentFactory > f1;
1666 css::uno::Reference< css::lang::XSingleServiceFactory > f2;
1667 loadImplementation(context, impl->info, &f1, &f2);
1668 osl::MutexGuard g(rBHelper.rMutex);
1669 if (!(isDisposed() || impl->loaded)) {
1670 impl->loaded = true;
1671 impl->factory1 = f1;
1672 impl->factory2 = f2;
1675 return impl;
1678 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */