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