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