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 { return configuration_provider::getImplementationName(); }
117
supportsService(rtl::OUString const & ServiceName)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
getSupportedServiceNames()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
createInstance(rtl::OUString const & aServiceSpecifier)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 >
createInstanceWithArguments(rtl::OUString const & ServiceSpecifier,css::uno::Sequence<css::uno::Any> const & Arguments)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
getAvailableServiceNames()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
refresh()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
addRefreshListener(css::uno::Reference<css::util::XRefreshListener> const & l)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
removeRefreshListener(css::uno::Reference<css::util::XRefreshListener> const & l)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
flush()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
addFlushListener(css::uno::Reference<css::util::XFlushListener> const & l)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
removeFlushListener(css::uno::Reference<css::util::XFlushListener> const & l)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
setLocale(css::lang::Locale const & eLocale)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
getLocale()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
flushModifications() const363 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:
Factory()378 Factory() {}
379
380 private:
~Factory()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
getImplementationName()392 virtual rtl::OUString SAL_CALL getImplementationName()
393 { return configuration_provider::getImplementationName(); }
394
supportsService(rtl::OUString const & ServiceName)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
getSupportedServiceNames()399 getSupportedServiceNames()
400 { return configuration_provider::getSupportedServiceNames(); }
401 };
402
createInstanceWithContext(css::uno::Reference<css::uno::XComponentContext> const & Context)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 >
createInstanceWithArgumentsAndContext(css::uno::Sequence<css::uno::Any> const & Arguments,css::uno::Reference<css::uno::XComponentContext> const & Context)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
createDefault(css::uno::Reference<css::uno::XComponentContext> const & context)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
getImplementationName()495 rtl::OUString getImplementationName() {
496 return rtl::OUString(
497 RTL_CONSTASCII_USTRINGPARAM(
498 "com.sun.star.comp.configuration.ConfigurationProvider"));
499 }
500
getSupportedServiceNames()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 >
createFactory(cppu::ComponentFactoryFunc,rtl::OUString const &,css::uno::Sequence<rtl::OUString> const &,rtl_ModuleCount *)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