1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 #include "precompiled_configmgr.hxx" 29 #include "sal/config.h" 30 31 #include <vector> 32 33 #include "boost/noncopyable.hpp" 34 #include "com/sun/star/beans/NamedValue.hpp" 35 #include "com/sun/star/beans/PropertyValue.hpp" 36 #include "com/sun/star/lang/EventObject.hpp" 37 #include "com/sun/star/lang/Locale.hpp" 38 #include "com/sun/star/lang/XLocalizable.hpp" 39 #include "com/sun/star/lang/XMultiServiceFactory.hpp" 40 #include "com/sun/star/lang/XServiceInfo.hpp" 41 #include "com/sun/star/lang/XSingleComponentFactory.hpp" 42 #include "com/sun/star/uno/Any.hxx" 43 #include "com/sun/star/uno/DeploymentException.hpp" 44 #include "com/sun/star/uno/Exception.hpp" 45 #include "com/sun/star/uno/Reference.hxx" 46 #include "com/sun/star/uno/RuntimeException.hpp" 47 #include "com/sun/star/uno/Sequence.hxx" 48 #include "com/sun/star/uno/XComponentContext.hpp" 49 #include "com/sun/star/uno/XInterface.hpp" 50 #include "com/sun/star/util/XFlushListener.hpp" 51 #include "com/sun/star/util/XFlushable.hpp" 52 #include "com/sun/star/util/XRefreshListener.hpp" 53 #include "com/sun/star/util/XRefreshable.hpp" 54 #include "comphelper/locale.hxx" 55 #include "cppu/unotype.hxx" 56 #include "cppuhelper/compbase5.hxx" 57 #include "cppuhelper/factory.hxx" 58 #include "cppuhelper/implbase2.hxx" 59 #include "cppuhelper/interfacecontainer.hxx" 60 #include "cppuhelper/weak.hxx" 61 #include "osl/diagnose.h" 62 #include "osl/mutex.hxx" 63 #include "sal/types.h" 64 #include "rtl/ref.hxx" 65 #include "rtl/unload.h" 66 #include "rtl/ustring.h" 67 #include "rtl/ustring.hxx" 68 69 #include "components.hxx" 70 #include "configurationprovider.hxx" 71 #include "lock.hxx" 72 #include "rootaccess.hxx" 73 74 namespace configmgr { namespace configuration_provider { 75 76 namespace { 77 78 namespace css = com::sun::star; 79 80 char const accessServiceName[] = 81 "com.sun.star.configuration.ConfigurationAccess"; 82 char const updateAccessServiceName[] = 83 "com.sun.star.configuration.ConfigurationUpdateAccess"; 84 85 void badNodePath() { 86 throw css::uno::Exception( 87 rtl::OUString( 88 RTL_CONSTASCII_USTRINGPARAM( 89 "com.sun.star.configuration.ConfigurationProvider expects a" 90 " single, non-empty, string nodepath argument")), 91 0); 92 } 93 94 typedef 95 cppu::WeakComponentImplHelper5< 96 css::lang::XServiceInfo, css::lang::XMultiServiceFactory, 97 css::util::XRefreshable, css::util::XFlushable, 98 css::lang::XLocalizable > 99 ServiceBase; 100 101 class Service: 102 private osl::Mutex, public ServiceBase, private boost::noncopyable 103 { 104 public: 105 Service( 106 css::uno::Reference< css::uno::XComponentContext > const context, 107 rtl::OUString const & locale): 108 ServiceBase(*static_cast< osl::Mutex * >(this)), context_(context), 109 locale_(locale) 110 { 111 OSL_ASSERT(context.is()); 112 } 113 114 private: 115 virtual ~Service() {} 116 117 virtual void SAL_CALL disposing() { flushModifications(); } 118 119 virtual rtl::OUString SAL_CALL getImplementationName() 120 throw (css::uno::RuntimeException) 121 { return configuration_provider::getImplementationName(); } 122 123 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) 124 throw (css::uno::RuntimeException) 125 { return ServiceName == getSupportedServiceNames()[0]; } //TODO 126 127 virtual css::uno::Sequence< rtl::OUString > SAL_CALL 128 getSupportedServiceNames() throw (css::uno::RuntimeException) 129 { return configuration_provider::getSupportedServiceNames(); } 130 131 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( 132 rtl::OUString const & aServiceSpecifier) 133 throw (css::uno::Exception, css::uno::RuntimeException); 134 135 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL 136 createInstanceWithArguments( 137 rtl::OUString const & ServiceSpecifier, 138 css::uno::Sequence< css::uno::Any > const & Arguments) 139 throw (css::uno::Exception, css::uno::RuntimeException); 140 141 virtual css::uno::Sequence< rtl::OUString > SAL_CALL 142 getAvailableServiceNames() throw (css::uno::RuntimeException); 143 144 virtual void SAL_CALL refresh() throw (css::uno::RuntimeException); 145 146 virtual void SAL_CALL addRefreshListener( 147 css::uno::Reference< css::util::XRefreshListener > const & l) 148 throw (css::uno::RuntimeException); 149 150 virtual void SAL_CALL removeRefreshListener( 151 css::uno::Reference< css::util::XRefreshListener > const & l) 152 throw (css::uno::RuntimeException); 153 154 virtual void SAL_CALL flush() throw (css::uno::RuntimeException); 155 156 virtual void SAL_CALL addFlushListener( 157 css::uno::Reference< css::util::XFlushListener > const & l) 158 throw (css::uno::RuntimeException); 159 160 virtual void SAL_CALL removeFlushListener( 161 css::uno::Reference< css::util::XFlushListener > const & l) 162 throw (css::uno::RuntimeException); 163 164 virtual void SAL_CALL setLocale(css::lang::Locale const & eLocale) 165 throw (css::uno::RuntimeException); 166 167 virtual css::lang::Locale SAL_CALL getLocale() 168 throw (css::uno::RuntimeException); 169 170 void flushModifications() const; 171 172 css::uno::Reference< css::uno::XComponentContext > context_; 173 rtl::OUString locale_; 174 }; 175 176 css::uno::Reference< css::uno::XInterface > Service::createInstance( 177 rtl::OUString const & aServiceSpecifier) 178 throw (css::uno::Exception, css::uno::RuntimeException) 179 { 180 return createInstanceWithArguments( 181 aServiceSpecifier, css::uno::Sequence< css::uno::Any >()); 182 } 183 184 css::uno::Reference< css::uno::XInterface > 185 Service::createInstanceWithArguments( 186 rtl::OUString const & ServiceSpecifier, 187 css::uno::Sequence< css::uno::Any > const & Arguments) 188 throw (css::uno::Exception, css::uno::RuntimeException) 189 { 190 rtl::OUString nodepath; 191 rtl::OUString locale; 192 for (sal_Int32 i = 0; i < Arguments.getLength(); ++i) { 193 css::beans::NamedValue v1; 194 css::beans::PropertyValue v2; 195 rtl::OUString name; 196 css::uno::Any value; 197 if (Arguments[i] >>= v1) { 198 name = v1.Name; 199 value = v1.Value; 200 } else if (Arguments[i] >>= v2) { 201 name = v2.Name; 202 value = v2.Value; 203 } else if (Arguments.getLength() == 1 && (Arguments[i] >>= nodepath)) { 204 // For backwards compatibility, allow a single string argument that 205 // denotes nodepath. 206 if (nodepath.getLength() == 0) { 207 badNodePath(); 208 } 209 break; 210 } else { 211 throw css::uno::Exception( 212 rtl::OUString( 213 RTL_CONSTASCII_USTRINGPARAM( 214 "com.sun.star.configuration.ConfigurationProvider" 215 " expects NamedValue or PropertyValue arguments")), 216 0); 217 } 218 // For backwards compatibility, allow "nodepath" and "Locale" in any 219 // case: 220 if (name.equalsIgnoreAsciiCaseAsciiL( 221 RTL_CONSTASCII_STRINGPARAM("nodepath"))) 222 { 223 if (nodepath.getLength() != 0 || !(value >>= nodepath) || 224 nodepath.getLength() == 0) 225 { 226 badNodePath(); 227 } 228 } else if (name.equalsIgnoreAsciiCaseAsciiL( 229 RTL_CONSTASCII_STRINGPARAM("locale"))) 230 { 231 if (locale.getLength() != 0 || !(value >>= locale) || 232 locale.getLength() == 0) 233 { 234 throw css::uno::Exception( 235 rtl::OUString( 236 RTL_CONSTASCII_USTRINGPARAM( 237 "com.sun.star.configuration.ConfigurationProvider" 238 " expects at most one, non-empty, string Locale" 239 " argument")), 240 0); 241 } 242 } 243 } 244 if (nodepath.getLength() == 0) { 245 badNodePath(); 246 } 247 // For backwards compatibility, allow a nodepath that misses the leading 248 // slash: 249 if (nodepath[0] != '/') { 250 nodepath = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")) + nodepath; 251 } 252 if (locale.getLength() == 0) { 253 //TODO: should the Access use the dynamically changing locale_ instead? 254 locale = locale_; 255 if (locale.getLength() == 0) { 256 locale = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en-US")); 257 } 258 } 259 bool update; 260 if (ServiceSpecifier.equalsAsciiL( 261 RTL_CONSTASCII_STRINGPARAM(accessServiceName))) 262 { 263 update = false; 264 } else if (ServiceSpecifier.equalsAsciiL( 265 RTL_CONSTASCII_STRINGPARAM(updateAccessServiceName))) 266 { 267 update = true; 268 } else { 269 throw css::uno::Exception( 270 (rtl::OUString( 271 RTL_CONSTASCII_USTRINGPARAM( 272 "com.sun.star.configuration.ConfigurationProvider does not" 273 " support service ")) + 274 ServiceSpecifier), 275 static_cast< cppu::OWeakObject * >(this)); 276 } 277 osl::MutexGuard guard(lock); 278 Components & components = Components::getSingleton(context_); 279 rtl::Reference< RootAccess > root( 280 new RootAccess(components, nodepath, locale, update)); 281 if (root->isValue()) { 282 throw css::uno::Exception( 283 (rtl::OUString( 284 RTL_CONSTASCII_USTRINGPARAM( 285 "com.sun.star.configuration.ConfigurationProvider: there is" 286 " a leaf value at nodepath ")) + 287 nodepath), 288 static_cast< cppu::OWeakObject * >(this)); 289 } 290 components.addRootAccess(root); 291 return static_cast< cppu::OWeakObject * >(root.get()); 292 } 293 294 css::uno::Sequence< rtl::OUString > Service::getAvailableServiceNames() 295 throw (css::uno::RuntimeException) 296 { 297 css::uno::Sequence< rtl::OUString > names(2); 298 names[0] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(accessServiceName)); 299 names[1] = rtl::OUString( 300 RTL_CONSTASCII_USTRINGPARAM(updateAccessServiceName)); 301 return names; 302 } 303 304 void Service::refresh() throw (css::uno::RuntimeException) { 305 //TODO 306 cppu::OInterfaceContainerHelper * cont = rBHelper.getContainer( 307 cppu::UnoType< css::util::XRefreshListener >::get()); 308 if (cont != 0) { 309 css::lang::EventObject ev(static_cast< cppu::OWeakObject * >(this)); 310 cont->notifyEach(&css::util::XRefreshListener::refreshed, ev); 311 } 312 } 313 314 void Service::addRefreshListener( 315 css::uno::Reference< css::util::XRefreshListener > const & l) 316 throw (css::uno::RuntimeException) 317 { 318 rBHelper.addListener( 319 cppu::UnoType< css::util::XRefreshListener >::get(), l); 320 } 321 322 void Service::removeRefreshListener( 323 css::uno::Reference< css::util::XRefreshListener > const & l) 324 throw (css::uno::RuntimeException) 325 { 326 rBHelper.removeListener( 327 cppu::UnoType< css::util::XRefreshListener >::get(), l); 328 } 329 330 void Service::flush() throw (css::uno::RuntimeException) { 331 flushModifications(); 332 cppu::OInterfaceContainerHelper * cont = rBHelper.getContainer( 333 cppu::UnoType< css::util::XFlushListener >::get()); 334 if (cont != 0) { 335 css::lang::EventObject ev(static_cast< cppu::OWeakObject * >(this)); 336 cont->notifyEach(&css::util::XFlushListener::flushed, ev); 337 } 338 } 339 340 void Service::addFlushListener( 341 css::uno::Reference< css::util::XFlushListener > const & l) 342 throw (css::uno::RuntimeException) 343 { 344 rBHelper.addListener(cppu::UnoType< css::util::XFlushListener >::get(), l); 345 } 346 347 void Service::removeFlushListener( 348 css::uno::Reference< css::util::XFlushListener > const & l) 349 throw (css::uno::RuntimeException) 350 { 351 rBHelper.removeListener( 352 cppu::UnoType< css::util::XFlushListener >::get(), l); 353 } 354 355 void Service::setLocale(css::lang::Locale const & eLocale) 356 throw (css::uno::RuntimeException) 357 { 358 osl::MutexGuard guard(lock); 359 locale_ = comphelper::Locale( 360 eLocale.Language, eLocale.Country, eLocale.Variant).toISO(); 361 } 362 363 css::lang::Locale Service::getLocale() throw (css::uno::RuntimeException) { 364 osl::MutexGuard guard(lock); 365 css::lang::Locale loc; 366 if (locale_.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("*"))) { 367 loc.Language = locale_; 368 } else if (locale_.getLength() != 0) { 369 try { 370 comphelper::Locale l(locale_); 371 loc.Language = l.getLanguage(); 372 loc.Country = l.getCountry(); 373 loc.Variant = l.getVariant(); 374 } catch (comphelper::Locale::MalFormedLocaleException & e) { 375 throw css::uno::RuntimeException( 376 (rtl::OUString( 377 RTL_CONSTASCII_USTRINGPARAM("MalformedLocaleException: ")) + 378 e.Message), 379 static_cast< cppu::OWeakObject * >(this)); 380 } 381 } 382 return loc; 383 } 384 385 void Service::flushModifications() const { 386 Components * components; 387 { 388 osl::MutexGuard guard(lock); 389 components = &Components::getSingleton(context_); 390 } 391 components->flushModifications(); 392 } 393 394 class Factory: 395 public cppu::WeakImplHelper2< 396 css::lang::XSingleComponentFactory, css::lang::XServiceInfo >, 397 private boost::noncopyable 398 { 399 public: 400 Factory() {} 401 402 private: 403 virtual ~Factory() {} 404 405 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL 406 createInstanceWithContext( 407 css::uno::Reference< css::uno::XComponentContext > const & Context) 408 throw (css::uno::Exception, css::uno::RuntimeException); 409 410 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL 411 createInstanceWithArgumentsAndContext( 412 css::uno::Sequence< css::uno::Any > const & Arguments, 413 css::uno::Reference< css::uno::XComponentContext > const & Context) 414 throw (css::uno::Exception, css::uno::RuntimeException); 415 416 virtual rtl::OUString SAL_CALL getImplementationName() 417 throw (css::uno::RuntimeException) 418 { return configuration_provider::getImplementationName(); } 419 420 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) 421 throw (css::uno::RuntimeException) 422 { return ServiceName == getSupportedServiceNames()[0]; } //TODO 423 424 virtual css::uno::Sequence< rtl::OUString > SAL_CALL 425 getSupportedServiceNames() throw (css::uno::RuntimeException) 426 { return configuration_provider::getSupportedServiceNames(); } 427 }; 428 429 css::uno::Reference< css::uno::XInterface > Factory::createInstanceWithContext( 430 css::uno::Reference< css::uno::XComponentContext > const & Context) 431 throw (css::uno::Exception, css::uno::RuntimeException) 432 { 433 return createInstanceWithArgumentsAndContext( 434 css::uno::Sequence< css::uno::Any >(), Context); 435 } 436 437 css::uno::Reference< css::uno::XInterface > 438 Factory::createInstanceWithArgumentsAndContext( 439 css::uno::Sequence< css::uno::Any > const & Arguments, 440 css::uno::Reference< css::uno::XComponentContext > const & Context) 441 throw (css::uno::Exception, css::uno::RuntimeException) 442 { 443 if (Arguments.getLength() == 0) { 444 css::uno::Reference< css::uno::XInterface > instance; 445 if (!(Context->getValueByName( 446 rtl::OUString( 447 RTL_CONSTASCII_USTRINGPARAM( 448 "/singletons/" 449 "com.sun.star.configuration.theDefaultProvider"))) 450 >>= instance) || 451 !instance.is()) 452 { 453 throw css::uno::DeploymentException( 454 rtl::OUString( 455 RTL_CONSTASCII_USTRINGPARAM( 456 "component context fails to supply singleton" 457 " com.sun.star.configuration.theDefaultProvider")), 458 Context); 459 } 460 return instance; 461 } else { 462 rtl::OUString locale; 463 for (sal_Int32 i = 0; i < Arguments.getLength(); ++i) { 464 css::beans::NamedValue v1; 465 css::beans::PropertyValue v2; 466 rtl::OUString name; 467 css::uno::Any value; 468 if (Arguments[i] >>= v1) { 469 name = v1.Name; 470 value = v1.Value; 471 } else if (Arguments[i] >>= v2) { 472 name = v2.Name; 473 value = v2.Value; 474 } else { 475 throw css::uno::Exception( 476 rtl::OUString( 477 RTL_CONSTASCII_USTRINGPARAM( 478 "com.sun.star.configuration.ConfigurationProvider" 479 " factory expects NamedValue or PropertyValue" 480 " arguments")), 481 0); 482 } 483 // For backwards compatibility, allow "Locale" and (ignored) 484 // "EnableAsync" in any case: 485 if (name.equalsIgnoreAsciiCaseAsciiL( 486 RTL_CONSTASCII_STRINGPARAM("locale"))) 487 { 488 if (locale.getLength() != 0 || !(value >>= locale) || 489 locale.getLength() == 0) 490 { 491 throw css::uno::Exception( 492 rtl::OUString( 493 RTL_CONSTASCII_USTRINGPARAM( 494 "com.sun.star.configuration." 495 "ConfigurationProvider factory expects at most" 496 " one, non-empty, string Locale argument")), 497 0); 498 } 499 } else if (!name.equalsIgnoreAsciiCaseAsciiL( 500 RTL_CONSTASCII_STRINGPARAM("enableasync"))) 501 { 502 throw css::uno::Exception( 503 rtl::OUString( 504 RTL_CONSTASCII_USTRINGPARAM( 505 "com.sun.star.configuration.ConfigurationProvider" 506 " factory: unknown argument ")) + name, 507 0); 508 } 509 } 510 return static_cast< cppu::OWeakObject * >(new Service(Context, locale)); 511 } 512 } 513 514 } 515 516 css::uno::Reference< css::uno::XInterface > createDefault( 517 css::uno::Reference< css::uno::XComponentContext > const & context) 518 { 519 return static_cast< cppu::OWeakObject * >( 520 new Service(context, rtl::OUString())); 521 } 522 523 rtl::OUString getImplementationName() { 524 return rtl::OUString( 525 RTL_CONSTASCII_USTRINGPARAM( 526 "com.sun.star.comp.configuration.ConfigurationProvider")); 527 } 528 529 css::uno::Sequence< rtl::OUString > getSupportedServiceNames() { 530 rtl::OUString name( 531 RTL_CONSTASCII_USTRINGPARAM( 532 "com.sun.star.configuration.ConfigurationProvider")); 533 return css::uno::Sequence< rtl::OUString >(&name, 1); 534 } 535 536 css::uno::Reference< css::lang::XSingleComponentFactory > 537 createFactory( 538 cppu::ComponentFactoryFunc, rtl::OUString const &, 539 css::uno::Sequence< rtl::OUString > const &, rtl_ModuleCount *) 540 SAL_THROW(()) 541 { 542 return new Factory; 543 } 544 545 } } 546