LibreOffice Module comphelper (master)  1
configuration.cxx
Go to the documentation of this file.
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 
10 #include <sal/config.h>
11 
12 #include <cassert>
13 #include <mutex>
14 #include <string_view>
15 #include <unordered_map>
16 
17 #include <com/sun/star/beans/NamedValue.hpp>
18 #include <com/sun/star/beans/PropertyAttribute.hpp>
19 #include <com/sun/star/configuration/ReadOnlyAccess.hpp>
20 #include <com/sun/star/configuration/ReadWriteAccess.hpp>
21 #include <com/sun/star/configuration/XReadWriteAccess.hpp>
22 #include <com/sun/star/configuration/theDefaultProvider.hpp>
23 #include <com/sun/star/container/XHierarchicalNameAccess.hpp>
24 #include <com/sun/star/container/XHierarchicalNameReplace.hpp>
25 #include <com/sun/star/container/XNameAccess.hpp>
26 #include <com/sun/star/container/XNameContainer.hpp>
27 #include <com/sun/star/lang/XLocalizable.hpp>
28 #include <com/sun/star/uno/Any.hxx>
29 #include <com/sun/star/uno/Reference.hxx>
30 #include <com/sun/star/util/XChangesListener.hpp>
31 #include <com/sun/star/util/XChangesNotifier.hpp>
35 #include <cppuhelper/implbase.hxx>
36 #include <rtl/ustring.hxx>
37 #include <sal/log.hxx>
39 
40 namespace com::sun::star::uno { class XComponentContext; }
41 
42 namespace {
43 
44 OUString getDefaultLocale(
45  css::uno::Reference< css::uno::XComponentContext > const & context)
46 {
47  return LanguageTag(
48  css::uno::Reference< css::lang::XLocalizable >(
49  css::configuration::theDefaultProvider::get(context),
50  css::uno::UNO_QUERY_THROW)->
51  getLocale()).getBcp47(false);
52 }
53 
54 OUString extendLocalizedPath(std::u16string_view path, OUString const & locale) {
56  locale.match("*"), "comphelper",
57  "Locale \"" << locale << "\" starts with \"*\"");
58  assert(locale.indexOf('&') == -1);
59  assert(locale.indexOf('"') == -1);
60  assert(locale.indexOf('\'') == -1);
61  return OUString::Concat(path) + "/['*" + locale + "']";
62 }
63 
64 }
65 
66 std::shared_ptr< comphelper::ConfigurationChanges >
68 {
70 }
71 
73 
75  access_->commitChanges();
76 }
77 
79  css::uno::Reference< css::uno::XComponentContext > const & context):
80  access_(
81  css::configuration::ReadWriteAccess::create(
82  context, getDefaultLocale(context)))
83 {}
84 
86  OUString const & path, css::uno::Any const & value) const
87 {
88  access_->replaceByHierarchicalName(path, value);
89 }
90 
91 css::uno::Reference< css::container::XHierarchicalNameReplace >
92 comphelper::ConfigurationChanges::getGroup(OUString const & path) const
93 {
94  return css::uno::Reference< css::container::XHierarchicalNameReplace >(
95  access_->getByHierarchicalName(path), css::uno::UNO_QUERY_THROW);
96 }
97 
98 css::uno::Reference< css::container::XNameContainer >
99 comphelper::ConfigurationChanges::getSet(OUString const & path) const
100 {
101  return css::uno::Reference< css::container::XNameContainer >(
102  access_->getByHierarchicalName(path), css::uno::UNO_QUERY_THROW);
103 }
104 
107 {
109  return WRAPPER;
110 }
111 
112 namespace
113 {
114 std::mutex gMutex;
115 std::unordered_map<OUString, css::uno::Any> gPropertyCache;
116 css::uno::Reference< css::util::XChangesNotifier > gNotifier;
117 css::uno::Reference< css::util::XChangesListener > gListener;
118 
119 class ConfigurationChangesListener
120  : public ::cppu::WeakImplHelper<css::util::XChangesListener>
121 {
122 public:
123  ConfigurationChangesListener()
124  {}
125  // util::XChangesListener
126  virtual void SAL_CALL changesOccurred( const css::util::ChangesEvent& ) override
127  {
128  std::scoped_lock aGuard(gMutex);
129  gPropertyCache.clear();
130  }
131  virtual void SAL_CALL disposing(const css::lang::EventObject&) override {}
132 };
133 
134 } // namespace
135 
138  access_(css::configuration::ReadWriteAccess::create(context_, "*"))
139 {
140  // Set up a configuration notifier to invalidate the cache as needed.
141  try
142  {
143  css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider(
144  css::configuration::theDefaultProvider::get( context_ ) );
145 
146  // set root path
147  css::uno::Sequence< css::uno::Any > params {
148  css::uno::Any( css::beans::NamedValue{ "nodepath", css::uno::Any( OUString("/"))} ),
149  css::uno::Any( css::beans::NamedValue{ "locale", css::uno::Any( OUString("*"))} ) };
150 
151  css::uno::Reference< css::uno::XInterface > xCfg
152  = xConfigProvider->createInstanceWithArguments(u"com.sun.star.configuration.ConfigurationAccess",
153  params);
154 
155  gNotifier = css::uno::Reference< css::util::XChangesNotifier >(xCfg, css::uno::UNO_QUERY);
156  assert(gNotifier.is());
157  gListener = css::uno::Reference< ConfigurationChangesListener >(new ConfigurationChangesListener());
158  gNotifier->addChangesListener(gListener);
159  }
160  catch(const css::uno::Exception&)
161  {
162  assert(false);
163  }
164 }
165 
167 {
168  gPropertyCache.clear();
169  gNotifier.clear();
170  gListener.clear();
171 }
172 
174  const
175 {
176  return
177  (access_->getPropertyByHierarchicalName(path).Attributes
178  & css::beans::PropertyAttribute::READONLY)
179  != 0;
180 }
181 
182 css::uno::Any comphelper::detail::ConfigurationWrapper::getPropertyValue(OUString const& path) const
183 {
184  std::scoped_lock aGuard(gMutex);
185  // Cache the configuration access, since some of the keys are used in hot code.
186  auto it = gPropertyCache.find(path);
187  if( it != gPropertyCache.end())
188  return it->second;
189 
190  sal_Int32 idx = path.lastIndexOf("/");
191  assert(idx!=-1);
192  OUString parentPath = path.copy(0, idx);
193  OUString childName = path.copy(idx+1);
194 
195  css::uno::Reference<css::container::XNameAccess> access(
196  access_->getByHierarchicalName(parentPath), css::uno::UNO_QUERY_THROW);
197  css::uno::Any property = access->getByName(childName);
198  gPropertyCache.emplace(path, property);
199  return property;
200 }
201 
203  std::shared_ptr< ConfigurationChanges > const & batch,
204  OUString const & path, css::uno::Any const & value)
205 {
206  assert(batch);
207  batch->setPropertyValue(path, value);
208 }
209 
210 css::uno::Any
212  std::u16string_view path) const
213 {
214  return access_->getByHierarchicalName(
215  extendLocalizedPath(path, getDefaultLocale(context_)));
216 }
217 
219  std::shared_ptr< ConfigurationChanges > const & batch,
220  OUString const & path, css::uno::Any const & value)
221 {
222  assert(batch);
223  batch->setPropertyValue(path, value);
224 }
225 
226 css::uno::Reference< css::container::XHierarchicalNameAccess >
228  OUString const & path) const
229 {
230  return css::uno::Reference< css::container::XHierarchicalNameAccess >(
231  (css::configuration::ReadOnlyAccess::create(
232  context_, getDefaultLocale(context_))->
233  getByHierarchicalName(path)),
234  css::uno::UNO_QUERY_THROW);
235 }
236 
237 css::uno::Reference< css::container::XHierarchicalNameReplace >
239  std::shared_ptr< ConfigurationChanges > const & batch,
240  OUString const & path)
241 {
242  assert(batch);
243  return batch->getGroup(path);
244 }
245 
246 css::uno::Reference< css::container::XNameAccess >
248  OUString const & path) const
249 {
250  return css::uno::Reference< css::container::XNameAccess >(
251  (css::configuration::ReadOnlyAccess::create(
252  context_, getDefaultLocale(context_))->
253  getByHierarchicalName(path)),
254  css::uno::UNO_QUERY_THROW);
255 }
256 
257 css::uno::Reference< css::container::XNameContainer >
259  std::shared_ptr< ConfigurationChanges > const & batch,
260  OUString const & path)
261 {
262  assert(batch);
263  return batch->getSet(path);
264 }
265 
266 std::shared_ptr< comphelper::ConfigurationChanges >
268  return std::shared_ptr< ConfigurationChanges >(
270 }
271 
273 {
274  maListeners.push_back( pListener );
275  mxConfig->addPropertyChangeListener( pListener->maName, this );
276  pListener->setProperty( mxConfig->getPropertyValue( pListener->maName ) );
277 }
278 
280 {
281  auto it = std::find( maListeners.begin(), maListeners.end(), pListener );
282  if ( it != maListeners.end() )
283  {
284  maListeners.erase( it );
285  mxConfig->removePropertyChangeListener( pListener->maName, this );
286  }
287 }
288 
290 {
291  for (auto const& listener : maListeners)
292  {
293  mxConfig->removePropertyChangeListener( listener->maName, this );
294  listener->dispose();
295  }
296  maListeners.clear();
297  mbDisposed = true;
298 }
299 
300 void SAL_CALL comphelper::ConfigurationListener::disposing(css::lang::EventObject const &)
301 {
302  dispose();
303 }
304 
306  css::beans::PropertyChangeEvent const &rEvt )
307 {
308  // Code is commonly used inside the SolarMutexGuard
309  // so to avoid concurrent writes to the property,
310  // and allow fast, lock-less access, guard here.
311  //
312  // Note that we are abusing rtl::Reference here to do acquire/release because,
313  // unlike osl::Guard, it is tolerant of null pointers, and on some code paths, the
314  // SolarMutex does not exist.
316 
317  assert( rEvt.Source == mxConfig );
318  for (auto const& listener : maListeners)
319  {
320  if ( listener->maName == rEvt.PropertyName )
321  {
322  // ignore rEvt.NewValue - in theory it could be stale => not set.
323  css::uno::Any aValue = mxConfig->getPropertyValue( listener->maName );
324  listener->setProperty( aValue );
325  }
326  }
327 }
328 
329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_Int8 value
static void setPropertyValue(std::shared_ptr< ConfigurationChanges > const &batch, OUString const &path, css::uno::Any const &value)
static std::shared_ptr< ConfigurationChanges > create()
SAL_DLLPRIVATE css::uno::Reference< css::container::XHierarchicalNameReplace > getGroup(OUString const &path) const
static css::uno::Reference< css::container::XHierarchicalNameReplace > getGroupReadWrite(std::shared_ptr< ConfigurationChanges > const &batch, OUString const &path)
const OUString & getBcp47(bool bResolveSystem=true) const
void dispose()
Release various circular references.
css::uno::Reference< css::configuration::XReadWriteAccess > access_
uno::Reference< uno::XComponentContext > context_
static ConfigurationWrapper const & get()
css::uno::Any getPropertyValue(OUString const &path) const
Reference< deployment::XPackageRegistry > create(Reference< deployment::XPackageRegistry > const &xRootRegistry, OUString const &context, OUString const &cachePath, Reference< XComponentContext > const &xComponentContext)
css::uno::Reference< css::container::XNameAccess > getSetReadOnly(OUString const &path) const
void addListener(ConfigurationListenerPropertyBase *pListener)
Listen for the specific property denoted by the listener.
float u
virtual void SAL_CALL disposing(css::lang::EventObject const &) override
css::uno::Any getLocalizedPropertyValue(std::u16string_view path) const
static void setLocalizedPropertyValue(std::shared_ptr< ConfigurationChanges > const &batch, OUString const &path, css::uno::Any const &value)
void removeListener(ConfigurationListenerPropertyBase *pListener)
Stop listening.
exports com.sun.star. configuration
const sal_uInt16 idx[]
static PropertyMapEntry const * find(const rtl::Reference< PropertySetInfo > &mxInfo, const OUString &aName) noexcept
const LanguageTag & getLocale()
Get the current LOK's locale.
Definition: lok.cxx:189
std::mutex mutex
Definition: random.cxx:41
#define SAL_WARN_IF(condition, area, stream)
A batch of configuration changes that is committed as a whole.
virtual void SAL_CALL propertyChange(css::beans::PropertyChangeEvent const &rEvt) override
Notify of the property change.
static SolarMutex * get()
Help components to get the SolarMutex easily.
Definition: solarmutex.cxx:34
css::uno::Reference< css::uno::XComponentContext > context_
Reference< XComponentContext > getProcessComponentContext()
This function gets the process service factory's default component context.
bool isReadOnly(OUString const &path) const
css::uno::Reference< css::uno::XInterface > access_
static css::uno::Reference< css::container::XNameContainer > getSetReadWrite(std::shared_ptr< ConfigurationChanges > const &batch, OUString const &path)
css::uno::Reference< css::container::XHierarchicalNameAccess > getGroupReadOnly(OUString const &path) const
SAL_DLLPRIVATE css::uno::Reference< css::container::XNameContainer > getSet(OUString const &path) const
void dispose()
virtual void setProperty(const css::uno::Any &aProperty)=0
SAL_DLLPRIVATE void setPropertyValue(OUString const &path, css::uno::Any const &value) const
std::shared_ptr< ConfigurationChanges > createChanges() const
ConfigurationChanges(const ConfigurationChanges &)=delete