xref: /trunk/main/configmgr/source/configurationprovider.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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