LibreOffice Module framework (master) 1
modulemanager.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 * 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 <com/sun/star/frame/UnknownModuleException.hpp>
23#include <com/sun/star/frame/XFrame.hpp>
24#include <com/sun/star/frame/XController.hpp>
25#include <com/sun/star/frame/XModel.hpp>
26#include <com/sun/star/frame/XModule.hpp>
27#include <com/sun/star/lang/XServiceInfo.hpp>
28#include <com/sun/star/frame/XModuleManager2.hpp>
29#include <com/sun/star/container/XNameReplace.hpp>
30#include <com/sun/star/container/XContainerQuery.hpp>
31#include <com/sun/star/uno/XComponentContext.hpp>
32
40#include <utility>
41
42namespace {
43
44class ModuleManager:
45 public cppu::WeakImplHelper<
46 css::lang::XServiceInfo,
47 css::frame::XModuleManager2,
48 css::container::XContainerQuery >
49{
50private:
51
55 css::uno::Reference< css::uno::XComponentContext > m_xContext;
56
61 css::uno::Reference< css::container::XNameAccess > m_xCFG;
62
63public:
64
65 explicit ModuleManager(css::uno::Reference< css::uno::XComponentContext > xContext);
66
67 ModuleManager(const ModuleManager&) = delete;
68 ModuleManager& operator=(const ModuleManager&) = delete;
69
70 // XServiceInfo
71 virtual OUString SAL_CALL getImplementationName() override;
72
73 virtual sal_Bool SAL_CALL supportsService(
74 OUString const & ServiceName) override;
75
76 virtual css::uno::Sequence< OUString > SAL_CALL
77 getSupportedServiceNames() override;
78
79 // XModuleManager
80 virtual OUString SAL_CALL identify(const css::uno::Reference< css::uno::XInterface >& xModule) override;
81
82 // XNameReplace
83 virtual void SAL_CALL replaceByName(const OUString& sName ,
84 const css::uno::Any& aValue) override;
85
86 // XNameAccess
87 virtual css::uno::Any SAL_CALL getByName(const OUString& sName) override;
88
89 virtual css::uno::Sequence< OUString > SAL_CALL getElementNames() override;
90
91 virtual sal_Bool SAL_CALL hasByName(const OUString& sName) override;
92
93 // XElementAccess
94 virtual css::uno::Type SAL_CALL getElementType() override;
95
96 virtual sal_Bool SAL_CALL hasElements() override;
97
98 // XContainerQuery
99 virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByQuery(const OUString& sQuery) override;
100
101 virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties) override;
102
103private:
104
125 OUString implts_identify(const css::uno::Reference< css::uno::XInterface >& xComponent);
126};
127
128ModuleManager::ModuleManager(css::uno::Reference< css::uno::XComponentContext > xContext)
129 : m_xContext(std::move(xContext))
130{
132 {
134 m_xContext, "/org.openoffice.Setup/Office/Factories",
136 css::uno::UNO_QUERY_THROW );
137 }
138}
139
140OUString ModuleManager::getImplementationName()
141{
142 return "com.sun.star.comp.framework.ModuleManager";
143}
144
145sal_Bool ModuleManager::supportsService(OUString const & ServiceName)
146{
147 return cppu::supportsService(this, ServiceName);
148}
149
150css::uno::Sequence< OUString > ModuleManager::getSupportedServiceNames()
151{
152 return { "com.sun.star.frame.ModuleManager" };
153}
154
155OUString SAL_CALL ModuleManager::identify(const css::uno::Reference< css::uno::XInterface >& xModule)
156{
157 // valid parameter?
158 css::uno::Reference< css::frame::XFrame > xFrame (xModule, css::uno::UNO_QUERY);
159 css::uno::Reference< css::awt::XWindow > xWindow (xModule, css::uno::UNO_QUERY);
160 css::uno::Reference< css::frame::XController > xController(xModule, css::uno::UNO_QUERY);
161 css::uno::Reference< css::frame::XModel > xModel (xModule, css::uno::UNO_QUERY);
162
163 if (
164 (!xFrame.is() ) &&
165 (!xWindow.is() ) &&
166 (!xController.is()) &&
167 (!xModel.is() )
168 )
169 {
170 throw css::lang::IllegalArgumentException(
171 "Given module is not a frame nor a window, controller or model.",
172 static_cast< ::cppu::OWeakObject* >(this),
173 1);
174 }
175
176 if (xFrame.is())
177 {
178 xController = xFrame->getController();
179 xWindow = xFrame->getComponentWindow();
180 }
181 if (xController.is())
182 xModel = xController->getModel();
183
184 // modules are implemented by the deepest component in hierarchy ...
185 // Means: model -> controller -> window
186 // No fallbacks to higher components are allowed !
187 // Note : A frame provides access to module components only ... but it's not a module by himself.
188
189 OUString sModule;
190 if (xModel.is())
191 sModule = implts_identify(xModel);
192 else if (xController.is())
193 sModule = implts_identify(xController);
194 else if (xWindow.is())
195 sModule = implts_identify(xWindow);
196
197 if (sModule.isEmpty())
198 throw css::frame::UnknownModuleException(
199 "Can not find suitable module for the given component.",
200 static_cast< ::cppu::OWeakObject* >(this));
201
202 return sModule;
203}
204
205void SAL_CALL ModuleManager::replaceByName(const OUString& sName ,
206 const css::uno::Any& aValue)
207{
208 ::comphelper::SequenceAsHashMap lProps(aValue);
209 if (lProps.empty() )
210 {
211 throw css::lang::IllegalArgumentException(
212 "No properties given to replace part of module.",
213 static_cast< cppu::OWeakObject * >(this),
214 2);
215 }
216
217 // get access to the element
218 // Note: Don't use impl_getConfig() method here. Because it creates a readonly access only, further
219 // it cache it as a member of this module manager instance. If we change some props there ... but don't
220 // flush changes (because an error occurred) we will read them later. If we use a different config access
221 // we can close it without a flush... and our read data won't be affected .-)
222 css::uno::Reference< css::uno::XInterface > xCfg = ::comphelper::ConfigurationHelper::openConfig(
224 "/org.openoffice.Setup/Office/Factories",
226 css::uno::Reference< css::container::XNameAccess > xModules (xCfg, css::uno::UNO_QUERY_THROW);
227 css::uno::Reference< css::container::XNameReplace > xModule ;
228
229 xModules->getByName(sName) >>= xModule;
230 if (!xModule.is())
231 {
232 throw css::uno::RuntimeException(
233 "Was not able to get write access to the requested module entry inside configuration.",
234 static_cast< cppu::OWeakObject * >(this));
235 }
236
237 for (auto const& prop : lProps)
238 {
239 // let "NoSuchElementException" out ! We support the same API ...
240 // and without a flush() at the end all changed data before will be ignored !
241 xModule->replaceByName(prop.first.maString, prop.second);
242 }
243
245}
246
247css::uno::Any SAL_CALL ModuleManager::getByName(const OUString& sName)
248{
249 // get access to the element
250 css::uno::Reference< css::container::XNameAccess > xModule;
251 if (m_xCFG)
252 m_xCFG->getByName(sName) >>= xModule;
253 if (!xModule.is())
254 {
255 throw css::uno::RuntimeException(
256 "Was not able to get write access to the requested module entry inside configuration.",
257 static_cast< cppu::OWeakObject * >(this));
258 }
259
260 // convert it to seq< PropertyValue >
261 const css::uno::Sequence< OUString > lPropNames = xModule->getElementNames();
263
264 lProps[OUString("ooSetupFactoryModuleIdentifier")] <<= sName;
265 for (const OUString& sPropName : lPropNames)
266 {
267 lProps[sPropName] = xModule->getByName(sPropName);
268 }
269
270 return css::uno::Any(lProps.getAsConstPropertyValueList());
271}
272
273css::uno::Sequence< OUString > SAL_CALL ModuleManager::getElementNames()
274{
275 return m_xCFG ? m_xCFG->getElementNames() : css::uno::Sequence<OUString>();
276}
277
278sal_Bool SAL_CALL ModuleManager::hasByName(const OUString& sName)
279{
280 return m_xCFG && m_xCFG->hasByName(sName);
281}
282
283css::uno::Type SAL_CALL ModuleManager::getElementType()
284{
286}
287
288sal_Bool SAL_CALL ModuleManager::hasElements()
289{
290 return m_xCFG && m_xCFG->hasElements();
291}
292
293css::uno::Reference< css::container::XEnumeration > SAL_CALL ModuleManager::createSubSetEnumerationByQuery(const OUString&)
294{
295 return css::uno::Reference< css::container::XEnumeration >();
296}
297
298css::uno::Reference< css::container::XEnumeration > SAL_CALL ModuleManager::createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties)
299{
300 ::comphelper::SequenceAsHashMap lSearchProps(lProperties);
301 const css::uno::Sequence< OUString > lModules = getElementNames();
302 ::std::vector< css::uno::Any > lResult;
303
304 for (const OUString& rModuleName : lModules)
305 {
306 try
307 {
308 ::comphelper::SequenceAsHashMap lModuleProps = getByName(rModuleName);
309 if (lModuleProps.match(lSearchProps))
310 lResult.push_back(css::uno::Any(lModuleProps.getAsConstPropertyValueList()));
311 }
312 catch(const css::uno::Exception&)
313 {
314 }
315 }
316
317 return new ::comphelper::OAnyEnumeration(comphelper::containerToSequence(lResult));
318}
319
320OUString ModuleManager::implts_identify(const css::uno::Reference< css::uno::XInterface >& xComponent)
321{
322 // Search for an optional (!) interface XModule first.
323 // It's used to overrule an existing service name. Used e.g. by our database form designer
324 // which uses a writer module internally.
325 css::uno::Reference< css::frame::XModule > xModule(xComponent, css::uno::UNO_QUERY);
326 if (xModule.is())
327 return xModule->getIdentifier();
328
329 // detect modules in a generic way...
330 // comparing service names with configured entries...
331 css::uno::Reference< css::lang::XServiceInfo > xInfo(xComponent, css::uno::UNO_QUERY);
332 if (!xInfo.is())
333 return OUString();
334
335 const css::uno::Sequence< OUString > lKnownModules = getElementNames();
336 for (const OUString& rName : lKnownModules)
337 {
338 if (xInfo->supportsService(rName))
339 return rName;
340 }
341
342 return OUString();
343}
344
345}
346
347extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
349 css::uno::XComponentContext *context,
350 css::uno::Sequence<css::uno::Any> const &)
351{
352 return cppu::acquire(new ModuleManager(context));
353}
354
355/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static css::uno::Reference< css::uno::XInterface > openConfig(const css::uno::Reference< css::uno::XComponentContext > &rxContext, const OUString &sPackage, EConfigurationModes eMode)
static void flush(const css::uno::Reference< css::uno::XInterface > &xCFG)
css::uno::Sequence< css::beans::PropertyValue > getAsConstPropertyValueList() const
bool match(const SequenceAsHashMap &rCheck) const
static bool IsFuzzing()
OUString sName
css::uno::Reference< css::uno::XComponentContext > m_xContext
SAL_DLLPUBLIC_EXPORT css::uno::XInterface * com_sun_star_comp_framework_ModuleManager_get_implementation(css::uno::XComponentContext *context, css::uno::Sequence< css::uno::Any > const &)
css::uno::Sequence< DstElementType > containerToSequence(const SrcType &i_Container)
css::uno::Sequence< OUString > getSupportedServiceNames()
OUString getImplementationName()
bool CPPUHELPER_DLLPUBLIC supportsService(css::lang::XServiceInfo *implementation, rtl::OUString const &name)
Reference< XController > xController
Reference< XFrame > xFrame
Reference< XModel > xModel
unsigned char sal_Bool