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 "cppu/unotype.hxx"
47 : #include "cppuhelper/compbase5.hxx"
48 : #include "cppuhelper/factory.hxx"
49 : #include "cppuhelper/implbase2.hxx"
50 : #include "cppuhelper/interfacecontainer.hxx"
51 : #include "cppuhelper/weak.hxx"
52 : #include "osl/mutex.hxx"
53 : #include "sal/types.h"
54 : #include "rtl/ref.hxx"
55 : #include "rtl/ustring.h"
56 : #include "rtl/ustring.hxx"
57 :
58 : #include <i18nlangtag/languagetag.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 154 : Service(
93 : css::uno::Reference< css::uno::XComponentContext > const context,
94 : OUString const & locale):
95 : ServiceBase(*static_cast< osl::Mutex * >(this)), context_(context),
96 154 : locale_(locale)
97 : {
98 154 : lock_ = lock();
99 : assert(context.is());
100 154 : }
101 :
102 : private:
103 284 : virtual ~Service() {}
104 :
105 153 : 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 61050 : 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 61050 : OUString nodepath;
180 122100 : OUString locale;
181 143150 : for (sal_Int32 i = 0; i < Arguments.getLength(); ++i) {
182 83162 : css::beans::NamedValue v1;
183 165262 : css::beans::PropertyValue v2;
184 165262 : OUString name;
185 165262 : css::uno::Any value;
186 83162 : if (Arguments[i] >>= v1) {
187 33705 : name = v1.Name;
188 33705 : value = v1.Value;
189 49457 : } else if (Arguments[i] >>= v2) {
190 48395 : name = v2.Name;
191 48395 : value = v2.Value;
192 1062 : } else if (Arguments.getLength() == 1 && (Arguments[i] >>= nodepath)) {
193 : // For backwards compatibility, allow a single string argument that
194 : // denotes nodepath.
195 1062 : if (nodepath.isEmpty()) {
196 0 : badNodePath();
197 : }
198 1062 : 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 82100 : if (name.equalsIgnoreAsciiCase("nodepath")) {
208 119976 : if (!nodepath.isEmpty() || !(value >>= nodepath) ||
209 59988 : nodepath.isEmpty())
210 : {
211 0 : badNodePath();
212 : }
213 22112 : } else if (name.equalsIgnoreAsciiCase("locale")) {
214 3416 : if (!locale.isEmpty() || !(value >>= locale) ||
215 1708 : locale.isEmpty())
216 : {
217 : throw css::uno::Exception(
218 : OUString("com.sun.star.configuration.ConfigurationProvider"
219 : " expects at most one, non-empty, string Locale"
220 : " argument"),
221 0 : 0);
222 : }
223 : }
224 82100 : }
225 61050 : if (nodepath.isEmpty()) {
226 0 : badNodePath();
227 : }
228 : // For backwards compatibility, allow a nodepath that misses the leading
229 : // slash:
230 61050 : if (nodepath[0] != '/') {
231 12416 : nodepath = OUString("/") + nodepath;
232 : }
233 61050 : if (locale.isEmpty()) {
234 : //TODO: should the Access use the dynamically changing locale_ instead?
235 59342 : locale = locale_;
236 59342 : if (locale.isEmpty()) {
237 16902 : locale = OUString("en-US");
238 : }
239 : }
240 : bool update;
241 61050 : if ( ServiceSpecifier == accessServiceName )
242 : {
243 43686 : update = false;
244 17364 : } else if ( ServiceSpecifier == updateAccessServiceName )
245 : {
246 17364 : update = true;
247 : } else {
248 : throw css::uno::Exception(
249 : (OUString("com.sun.star.configuration.ConfigurationProvider does not"
250 0 : " support service ") +
251 0 : ServiceSpecifier),
252 0 : static_cast< cppu::OWeakObject * >(this));
253 : }
254 122100 : osl::MutexGuard guard(*lock_);
255 61050 : Components & components = Components::getSingleton(context_);
256 : rtl::Reference< RootAccess > root(
257 122100 : new RootAccess(components, nodepath, locale, update));
258 61050 : if (root->isValue()) {
259 : throw css::uno::Exception(
260 : (OUString("com.sun.star.configuration.ConfigurationProvider: there is"
261 0 : " a leaf value at nodepath ") +
262 0 : nodepath),
263 0 : static_cast< cppu::OWeakObject * >(this));
264 : }
265 61050 : components.addRootAccess(root);
266 122100 : return static_cast< cppu::OWeakObject * >(root.get());
267 : }
268 :
269 2 : css::uno::Sequence< OUString > Service::getAvailableServiceNames()
270 : throw (css::uno::RuntimeException)
271 : {
272 2 : css::uno::Sequence< OUString > names(2);
273 2 : names[0] = OUString(RTL_CONSTASCII_USTRINGPARAM(accessServiceName));
274 2 : names[1] = OUString(RTL_CONSTASCII_USTRINGPARAM(updateAccessServiceName));
275 2 : return names;
276 : }
277 :
278 2 : void Service::refresh() throw (css::uno::RuntimeException) {
279 : //TODO
280 : cppu::OInterfaceContainerHelper * cont = rBHelper.getContainer(
281 2 : cppu::UnoType< css::util::XRefreshListener >::get());
282 2 : if (cont != 0) {
283 2 : css::lang::EventObject ev(static_cast< cppu::OWeakObject * >(this));
284 2 : cont->notifyEach(&css::util::XRefreshListener::refreshed, ev);
285 : }
286 2 : }
287 :
288 1 : void Service::addRefreshListener(
289 : css::uno::Reference< css::util::XRefreshListener > const & l)
290 : throw (css::uno::RuntimeException)
291 : {
292 : rBHelper.addListener(
293 1 : cppu::UnoType< css::util::XRefreshListener >::get(), l);
294 1 : }
295 :
296 1 : void Service::removeRefreshListener(
297 : css::uno::Reference< css::util::XRefreshListener > const & l)
298 : throw (css::uno::RuntimeException)
299 : {
300 : rBHelper.removeListener(
301 1 : cppu::UnoType< css::util::XRefreshListener >::get(), l);
302 1 : }
303 :
304 167 : void Service::flush() throw (css::uno::RuntimeException) {
305 167 : flushModifications();
306 : cppu::OInterfaceContainerHelper * cont = rBHelper.getContainer(
307 167 : cppu::UnoType< css::util::XFlushListener >::get());
308 167 : if (cont != 0) {
309 1 : css::lang::EventObject ev(static_cast< cppu::OWeakObject * >(this));
310 1 : cont->notifyEach(&css::util::XFlushListener::flushed, ev);
311 : }
312 167 : }
313 :
314 2 : void Service::addFlushListener(
315 : css::uno::Reference< css::util::XFlushListener > const & l)
316 : throw (css::uno::RuntimeException)
317 : {
318 2 : rBHelper.addListener(cppu::UnoType< css::util::XFlushListener >::get(), l);
319 2 : }
320 :
321 1 : void Service::removeFlushListener(
322 : css::uno::Reference< css::util::XFlushListener > const & l)
323 : throw (css::uno::RuntimeException)
324 : {
325 : rBHelper.removeListener(
326 1 : cppu::UnoType< css::util::XFlushListener >::get(), l);
327 1 : }
328 :
329 168 : void Service::setLocale(css::lang::Locale const & eLocale)
330 : throw (css::uno::RuntimeException)
331 : {
332 168 : osl::MutexGuard guard(*lock_);
333 168 : locale_ = LanguageTag( eLocale).getBcp47();
334 168 : }
335 :
336 3109 : css::lang::Locale Service::getLocale() throw (css::uno::RuntimeException) {
337 3109 : osl::MutexGuard guard(*lock_);
338 3109 : css::lang::Locale loc;
339 3109 : if (! locale_.isEmpty()) {
340 1654 : loc = LanguageTag( locale_).getLocale( false);
341 : }
342 3109 : return loc;
343 : }
344 :
345 320 : void Service::flushModifications() const {
346 : Components * components;
347 : {
348 320 : osl::MutexGuard guard(*lock_);
349 320 : components = &Components::getSingleton(context_);
350 : }
351 320 : components->flushModifications();
352 320 : }
353 :
354 : class Factory:
355 : public cppu::WeakImplHelper2<
356 : css::lang::XSingleComponentFactory, css::lang::XServiceInfo >,
357 : private boost::noncopyable
358 : {
359 : public:
360 36 : Factory() {}
361 :
362 : private:
363 72 : virtual ~Factory() {}
364 :
365 : virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
366 : createInstanceWithContext(
367 : css::uno::Reference< css::uno::XComponentContext > const & Context)
368 : throw (css::uno::Exception, css::uno::RuntimeException);
369 :
370 : virtual css::uno::Reference< css::uno::XInterface > SAL_CALL
371 : createInstanceWithArgumentsAndContext(
372 : css::uno::Sequence< css::uno::Any > const & Arguments,
373 : css::uno::Reference< css::uno::XComponentContext > const & Context)
374 : throw (css::uno::Exception, css::uno::RuntimeException);
375 :
376 0 : virtual OUString SAL_CALL getImplementationName()
377 : throw (css::uno::RuntimeException)
378 0 : { return configuration_provider::getImplementationName(); }
379 :
380 0 : virtual sal_Bool SAL_CALL supportsService(OUString const & ServiceName)
381 : throw (css::uno::RuntimeException)
382 0 : { return ServiceName == getSupportedServiceNames()[0]; } //TODO
383 :
384 : virtual css::uno::Sequence< OUString > SAL_CALL
385 0 : getSupportedServiceNames() throw (css::uno::RuntimeException)
386 0 : { return configuration_provider::getSupportedServiceNames(); }
387 : };
388 :
389 38 : css::uno::Reference< css::uno::XInterface > Factory::createInstanceWithContext(
390 : css::uno::Reference< css::uno::XComponentContext > const & Context)
391 : throw (css::uno::Exception, css::uno::RuntimeException)
392 : {
393 : return createInstanceWithArgumentsAndContext(
394 38 : css::uno::Sequence< css::uno::Any >(), Context);
395 : }
396 :
397 : css::uno::Reference< css::uno::XInterface >
398 39 : Factory::createInstanceWithArgumentsAndContext(
399 : css::uno::Sequence< css::uno::Any > const & Arguments,
400 : css::uno::Reference< css::uno::XComponentContext > const & Context)
401 : throw (css::uno::Exception, css::uno::RuntimeException)
402 : {
403 39 : if (Arguments.getLength() == 0) {
404 38 : return css::configuration::theDefaultProvider::get(Context);
405 : } else {
406 1 : OUString locale;
407 2 : for (sal_Int32 i = 0; i < Arguments.getLength(); ++i) {
408 1 : css::beans::NamedValue v1;
409 2 : css::beans::PropertyValue v2;
410 2 : OUString name;
411 2 : css::uno::Any value;
412 1 : if (Arguments[i] >>= v1) {
413 1 : name = v1.Name;
414 1 : value = v1.Value;
415 0 : } else if (Arguments[i] >>= v2) {
416 0 : name = v2.Name;
417 0 : value = v2.Value;
418 : } else {
419 : throw css::uno::Exception(
420 : OUString("com.sun.star.configuration.ConfigurationProvider"
421 : " factory expects NamedValue or PropertyValue"
422 : " arguments"),
423 0 : 0);
424 : }
425 : // For backwards compatibility, allow "Locale" and (ignored)
426 : // "EnableAsync" in any case:
427 1 : if (name.equalsIgnoreAsciiCase("locale")) {
428 2 : if (!locale.isEmpty() || !(value >>= locale) ||
429 1 : locale.isEmpty())
430 : {
431 : throw css::uno::Exception(
432 : OUString("com.sun.star.configuration."
433 : "ConfigurationProvider factory expects at most"
434 : " one, non-empty, string Locale argument"),
435 0 : 0);
436 : }
437 0 : } else if (!name.equalsIgnoreAsciiCase("enableasync")) {
438 : throw css::uno::Exception(
439 : OUString("com.sun.star.configuration.ConfigurationProvider"
440 0 : " factory: unknown argument ") + name,
441 0 : 0);
442 : }
443 1 : }
444 1 : return static_cast< cppu::OWeakObject * >(new Service(Context, locale));
445 : }
446 : }
447 :
448 : }
449 :
450 153 : css::uno::Reference< css::uno::XInterface > createDefault(
451 : css::uno::Reference< css::uno::XComponentContext > const & context)
452 : {
453 : return static_cast< cppu::OWeakObject * >(
454 153 : new Service(context, OUString()));
455 : }
456 :
457 436 : OUString getImplementationName() {
458 436 : return OUString("com.sun.star.comp.configuration.ConfigurationProvider");
459 : }
460 :
461 36 : css::uno::Sequence< OUString > getSupportedServiceNames() {
462 36 : OUString name("com.sun.star.configuration.ConfigurationProvider");
463 36 : return css::uno::Sequence< OUString >(&name, 1);
464 : }
465 :
466 : css::uno::Reference< css::lang::XSingleComponentFactory >
467 36 : createFactory(
468 : SAL_UNUSED_PARAMETER cppu::ComponentFactoryFunc,
469 : SAL_UNUSED_PARAMETER OUString const &,
470 : SAL_UNUSED_PARAMETER css::uno::Sequence< OUString > const &,
471 : SAL_UNUSED_PARAMETER rtl_ModuleCount *)
472 : SAL_THROW(())
473 : {
474 36 : return new Factory;
475 : }
476 :
477 : } }
478 :
479 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|