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
badNodePath()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:
Service(css::uno::Reference<css::uno::XComponentContext> const context,rtl::OUString const & locale)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:
~Service()111 virtual ~Service() {}
112
disposing()113 virtual void SAL_CALL disposing() { flushModifications(); }
114
getImplementationName()115 virtual rtl::OUString SAL_CALL getImplementationName()
116 throw (css::uno::RuntimeException)
117 { return configuration_provider::getImplementationName(); }
118
supportsService(rtl::OUString const & ServiceName)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
getSupportedServiceNames()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
createInstance(rtl::OUString const & aServiceSpecifier)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 >
createInstanceWithArguments(rtl::OUString const & ServiceSpecifier,css::uno::Sequence<css::uno::Any> const & Arguments)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
getAvailableServiceNames()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
refresh()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
addRefreshListener(css::uno::Reference<css::util::XRefreshListener> const & l)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
removeRefreshListener(css::uno::Reference<css::util::XRefreshListener> const & l)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
flush()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
addFlushListener(css::uno::Reference<css::util::XFlushListener> const & l)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
removeFlushListener(css::uno::Reference<css::util::XFlushListener> const & l)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
setLocale(css::lang::Locale const & eLocale)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
getLocale()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
flushModifications() const381 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:
Factory()396 Factory() {}
397
398 private:
~Factory()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
getImplementationName()412 virtual rtl::OUString SAL_CALL getImplementationName()
413 throw (css::uno::RuntimeException)
414 { return configuration_provider::getImplementationName(); }
415
supportsService(rtl::OUString const & ServiceName)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
getSupportedServiceNames()421 getSupportedServiceNames() throw (css::uno::RuntimeException)
422 { return configuration_provider::getSupportedServiceNames(); }
423 };
424
createInstanceWithContext(css::uno::Reference<css::uno::XComponentContext> const & Context)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 >
createInstanceWithArgumentsAndContext(css::uno::Sequence<css::uno::Any> const & Arguments,css::uno::Reference<css::uno::XComponentContext> const & Context)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
createDefault(css::uno::Reference<css::uno::XComponentContext> const & context)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
getImplementationName()519 rtl::OUString getImplementationName() {
520 return rtl::OUString(
521 RTL_CONSTASCII_USTRINGPARAM(
522 "com.sun.star.comp.configuration.ConfigurationProvider"));
523 }
524
getSupportedServiceNames()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 >
createFactory(cppu::ComponentFactoryFunc,rtl::OUString const &,css::uno::Sequence<rtl::OUString> const &,rtl_ModuleCount *)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