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 { return configuration_provider::getImplementationName(); } 117 118 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) 119 { return ServiceName == getSupportedServiceNames()[0]; } //TODO 120 121 virtual css::uno::Sequence< rtl::OUString > SAL_CALL 122 getSupportedServiceNames() 123 { return configuration_provider::getSupportedServiceNames(); } 124 125 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( 126 rtl::OUString const & aServiceSpecifier); 127 128 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL 129 createInstanceWithArguments( 130 rtl::OUString const & ServiceSpecifier, 131 css::uno::Sequence< css::uno::Any > const & Arguments); 132 133 virtual css::uno::Sequence< rtl::OUString > SAL_CALL 134 getAvailableServiceNames(); 135 136 virtual void SAL_CALL refresh(); 137 138 virtual void SAL_CALL addRefreshListener( 139 css::uno::Reference< css::util::XRefreshListener > const & l); 140 141 virtual void SAL_CALL removeRefreshListener( 142 css::uno::Reference< css::util::XRefreshListener > const & l); 143 144 virtual void SAL_CALL flush(); 145 146 virtual void SAL_CALL addFlushListener( 147 css::uno::Reference< css::util::XFlushListener > const & l); 148 149 virtual void SAL_CALL removeFlushListener( 150 css::uno::Reference< css::util::XFlushListener > const & l); 151 152 virtual void SAL_CALL setLocale(css::lang::Locale const & eLocale); 153 154 virtual css::lang::Locale SAL_CALL getLocale(); 155 156 void flushModifications() const; 157 158 css::uno::Reference< css::uno::XComponentContext > context_; 159 rtl::OUString locale_; 160 }; 161 162 css::uno::Reference< css::uno::XInterface > Service::createInstance( 163 rtl::OUString const & aServiceSpecifier) 164 { 165 return createInstanceWithArguments( 166 aServiceSpecifier, css::uno::Sequence< css::uno::Any >()); 167 } 168 169 css::uno::Reference< css::uno::XInterface > 170 Service::createInstanceWithArguments( 171 rtl::OUString const & ServiceSpecifier, 172 css::uno::Sequence< css::uno::Any > const & Arguments) 173 { 174 rtl::OUString nodepath; 175 rtl::OUString locale; 176 for (sal_Int32 i = 0; i < Arguments.getLength(); ++i) { 177 css::beans::NamedValue v1; 178 css::beans::PropertyValue v2; 179 rtl::OUString name; 180 css::uno::Any value; 181 if (Arguments[i] >>= v1) { 182 name = v1.Name; 183 value = v1.Value; 184 } else if (Arguments[i] >>= v2) { 185 name = v2.Name; 186 value = v2.Value; 187 } else if (Arguments.getLength() == 1 && (Arguments[i] >>= nodepath)) { 188 // For backwards compatibility, allow a single string argument that 189 // denotes nodepath. 190 if (nodepath.getLength() == 0) { 191 badNodePath(); 192 } 193 break; 194 } else { 195 throw css::uno::Exception( 196 rtl::OUString( 197 RTL_CONSTASCII_USTRINGPARAM( 198 "com.sun.star.configuration.ConfigurationProvider" 199 " expects NamedValue or PropertyValue arguments")), 200 0); 201 } 202 // For backwards compatibility, allow "nodepath" and "Locale" in any 203 // case: 204 if (name.equalsIgnoreAsciiCaseAsciiL( 205 RTL_CONSTASCII_STRINGPARAM("nodepath"))) 206 { 207 if (nodepath.getLength() != 0 || !(value >>= nodepath) || 208 nodepath.getLength() == 0) 209 { 210 badNodePath(); 211 } 212 } else if (name.equalsIgnoreAsciiCaseAsciiL( 213 RTL_CONSTASCII_STRINGPARAM("locale"))) 214 { 215 if (locale.getLength() != 0 || !(value >>= locale) || 216 locale.getLength() == 0) 217 { 218 throw css::uno::Exception( 219 rtl::OUString( 220 RTL_CONSTASCII_USTRINGPARAM( 221 "com.sun.star.configuration.ConfigurationProvider" 222 " expects at most one, non-empty, string Locale" 223 " argument")), 224 0); 225 } 226 } 227 } 228 if (nodepath.getLength() == 0) { 229 badNodePath(); 230 } 231 // For backwards compatibility, allow a nodepath that misses the leading 232 // slash: 233 if (nodepath[0] != '/') { 234 nodepath = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")) + nodepath; 235 } 236 if (locale.getLength() == 0) { 237 //TODO: should the Access use the dynamically changing locale_ instead? 238 locale = locale_; 239 if (locale.getLength() == 0) { 240 locale = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("en-US")); 241 } 242 } 243 bool update; 244 if (ServiceSpecifier.equalsAsciiL( 245 RTL_CONSTASCII_STRINGPARAM(accessServiceName))) 246 { 247 update = false; 248 } else if (ServiceSpecifier.equalsAsciiL( 249 RTL_CONSTASCII_STRINGPARAM(updateAccessServiceName))) 250 { 251 update = true; 252 } else { 253 throw css::uno::Exception( 254 (rtl::OUString( 255 RTL_CONSTASCII_USTRINGPARAM( 256 "com.sun.star.configuration.ConfigurationProvider does not" 257 " support service ")) + 258 ServiceSpecifier), 259 static_cast< cppu::OWeakObject * >(this)); 260 } 261 osl::MutexGuard guard(lock); 262 Components & components = Components::getSingleton(context_); 263 rtl::Reference< RootAccess > root( 264 new RootAccess(components, nodepath, locale, update)); 265 if (root->isValue()) { 266 throw css::uno::Exception( 267 (rtl::OUString( 268 RTL_CONSTASCII_USTRINGPARAM( 269 "com.sun.star.configuration.ConfigurationProvider: there is" 270 " a leaf value at nodepath ")) + 271 nodepath), 272 static_cast< cppu::OWeakObject * >(this)); 273 } 274 components.addRootAccess(root); 275 return static_cast< cppu::OWeakObject * >(root.get()); 276 } 277 278 css::uno::Sequence< rtl::OUString > Service::getAvailableServiceNames() 279 { 280 css::uno::Sequence< rtl::OUString > names(2); 281 names[0] = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(accessServiceName)); 282 names[1] = rtl::OUString( 283 RTL_CONSTASCII_USTRINGPARAM(updateAccessServiceName)); 284 return names; 285 } 286 287 void Service::refresh() { 288 //TODO 289 cppu::OInterfaceContainerHelper * cont = rBHelper.getContainer( 290 cppu::UnoType< css::util::XRefreshListener >::get()); 291 if (cont != 0) { 292 css::lang::EventObject ev(static_cast< cppu::OWeakObject * >(this)); 293 cont->notifyEach(&css::util::XRefreshListener::refreshed, ev); 294 } 295 } 296 297 void Service::addRefreshListener( 298 css::uno::Reference< css::util::XRefreshListener > const & l) 299 { 300 rBHelper.addListener( 301 cppu::UnoType< css::util::XRefreshListener >::get(), l); 302 } 303 304 void Service::removeRefreshListener( 305 css::uno::Reference< css::util::XRefreshListener > const & l) 306 { 307 rBHelper.removeListener( 308 cppu::UnoType< css::util::XRefreshListener >::get(), l); 309 } 310 311 void Service::flush() { 312 flushModifications(); 313 cppu::OInterfaceContainerHelper * cont = rBHelper.getContainer( 314 cppu::UnoType< css::util::XFlushListener >::get()); 315 if (cont != 0) { 316 css::lang::EventObject ev(static_cast< cppu::OWeakObject * >(this)); 317 cont->notifyEach(&css::util::XFlushListener::flushed, ev); 318 } 319 } 320 321 void Service::addFlushListener( 322 css::uno::Reference< css::util::XFlushListener > const & l) 323 { 324 rBHelper.addListener(cppu::UnoType< css::util::XFlushListener >::get(), l); 325 } 326 327 void Service::removeFlushListener( 328 css::uno::Reference< css::util::XFlushListener > const & l) 329 { 330 rBHelper.removeListener( 331 cppu::UnoType< css::util::XFlushListener >::get(), l); 332 } 333 334 void Service::setLocale(css::lang::Locale const & eLocale) 335 { 336 osl::MutexGuard guard(lock); 337 locale_ = comphelper::Locale( 338 eLocale.Language, eLocale.Country, eLocale.Variant).toISO(); 339 } 340 341 css::lang::Locale Service::getLocale() { 342 osl::MutexGuard guard(lock); 343 css::lang::Locale loc; 344 if (locale_.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("*"))) { 345 loc.Language = locale_; 346 } else if (locale_.getLength() != 0) { 347 try { 348 comphelper::Locale l(locale_); 349 loc.Language = l.getLanguage(); 350 loc.Country = l.getCountry(); 351 loc.Variant = l.getVariant(); 352 } catch (comphelper::Locale::MalFormedLocaleException & e) { 353 throw css::uno::RuntimeException( 354 (rtl::OUString( 355 RTL_CONSTASCII_USTRINGPARAM("MalformedLocaleException: ")) + 356 e.Message), 357 static_cast< cppu::OWeakObject * >(this)); 358 } 359 } 360 return loc; 361 } 362 363 void Service::flushModifications() const { 364 Components * components; 365 { 366 osl::MutexGuard guard(lock); 367 components = &Components::getSingleton(context_); 368 } 369 components->flushModifications(); 370 } 371 372 class Factory: 373 public cppu::WeakImplHelper2< 374 css::lang::XSingleComponentFactory, css::lang::XServiceInfo >, 375 private boost::noncopyable 376 { 377 public: 378 Factory() {} 379 380 private: 381 virtual ~Factory() {} 382 383 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL 384 createInstanceWithContext( 385 css::uno::Reference< css::uno::XComponentContext > const & Context); 386 387 virtual css::uno::Reference< css::uno::XInterface > SAL_CALL 388 createInstanceWithArgumentsAndContext( 389 css::uno::Sequence< css::uno::Any > const & Arguments, 390 css::uno::Reference< css::uno::XComponentContext > const & Context); 391 392 virtual rtl::OUString SAL_CALL getImplementationName() 393 { return configuration_provider::getImplementationName(); } 394 395 virtual sal_Bool SAL_CALL supportsService(rtl::OUString const & ServiceName) 396 { return ServiceName == getSupportedServiceNames()[0]; } //TODO 397 398 virtual css::uno::Sequence< rtl::OUString > SAL_CALL 399 getSupportedServiceNames() 400 { return configuration_provider::getSupportedServiceNames(); } 401 }; 402 403 css::uno::Reference< css::uno::XInterface > Factory::createInstanceWithContext( 404 css::uno::Reference< css::uno::XComponentContext > const & Context) 405 { 406 return createInstanceWithArgumentsAndContext( 407 css::uno::Sequence< css::uno::Any >(), Context); 408 } 409 410 css::uno::Reference< css::uno::XInterface > 411 Factory::createInstanceWithArgumentsAndContext( 412 css::uno::Sequence< css::uno::Any > const & Arguments, 413 css::uno::Reference< css::uno::XComponentContext > const & Context) 414 { 415 if (Arguments.getLength() == 0) { 416 css::uno::Reference< css::uno::XInterface > instance; 417 if (!(Context->getValueByName( 418 rtl::OUString( 419 RTL_CONSTASCII_USTRINGPARAM( 420 "/singletons/" 421 "com.sun.star.configuration.theDefaultProvider"))) 422 >>= instance) || 423 !instance.is()) 424 { 425 throw css::uno::DeploymentException( 426 rtl::OUString( 427 RTL_CONSTASCII_USTRINGPARAM( 428 "component context fails to supply singleton" 429 " com.sun.star.configuration.theDefaultProvider")), 430 Context); 431 } 432 return instance; 433 } else { 434 rtl::OUString locale; 435 for (sal_Int32 i = 0; i < Arguments.getLength(); ++i) { 436 css::beans::NamedValue v1; 437 css::beans::PropertyValue v2; 438 rtl::OUString name; 439 css::uno::Any value; 440 if (Arguments[i] >>= v1) { 441 name = v1.Name; 442 value = v1.Value; 443 } else if (Arguments[i] >>= v2) { 444 name = v2.Name; 445 value = v2.Value; 446 } else { 447 throw css::uno::Exception( 448 rtl::OUString( 449 RTL_CONSTASCII_USTRINGPARAM( 450 "com.sun.star.configuration.ConfigurationProvider" 451 " factory expects NamedValue or PropertyValue" 452 " arguments")), 453 0); 454 } 455 // For backwards compatibility, allow "Locale" and (ignored) 456 // "EnableAsync" in any case: 457 if (name.equalsIgnoreAsciiCaseAsciiL( 458 RTL_CONSTASCII_STRINGPARAM("locale"))) 459 { 460 if (locale.getLength() != 0 || !(value >>= locale) || 461 locale.getLength() == 0) 462 { 463 throw css::uno::Exception( 464 rtl::OUString( 465 RTL_CONSTASCII_USTRINGPARAM( 466 "com.sun.star.configuration." 467 "ConfigurationProvider factory expects at most" 468 " one, non-empty, string Locale argument")), 469 0); 470 } 471 } else if (!name.equalsIgnoreAsciiCaseAsciiL( 472 RTL_CONSTASCII_STRINGPARAM("enableasync"))) 473 { 474 throw css::uno::Exception( 475 rtl::OUString( 476 RTL_CONSTASCII_USTRINGPARAM( 477 "com.sun.star.configuration.ConfigurationProvider" 478 " factory: unknown argument ")) + name, 479 0); 480 } 481 } 482 return static_cast< cppu::OWeakObject * >(new Service(Context, locale)); 483 } 484 } 485 486 } 487 488 css::uno::Reference< css::uno::XInterface > createDefault( 489 css::uno::Reference< css::uno::XComponentContext > const & context) 490 { 491 return static_cast< cppu::OWeakObject * >( 492 new Service(context, rtl::OUString())); 493 } 494 495 rtl::OUString getImplementationName() { 496 return rtl::OUString( 497 RTL_CONSTASCII_USTRINGPARAM( 498 "com.sun.star.comp.configuration.ConfigurationProvider")); 499 } 500 501 css::uno::Sequence< rtl::OUString > getSupportedServiceNames() { 502 rtl::OUString name( 503 RTL_CONSTASCII_USTRINGPARAM( 504 "com.sun.star.configuration.ConfigurationProvider")); 505 return css::uno::Sequence< rtl::OUString >(&name, 1); 506 } 507 508 css::uno::Reference< css::lang::XSingleComponentFactory > 509 createFactory( 510 cppu::ComponentFactoryFunc, rtl::OUString const &, 511 css::uno::Sequence< rtl::OUString > const &, rtl_ModuleCount *) 512 SAL_THROW(()) 513 { 514 return new Factory; 515 } 516 517 } } 518