xref: /trunk/main/framework/source/services/modulemanager.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 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_framework.hxx"
26 
27 #include "services/modulemanager.hxx"
28 #include "services/frame.hxx"
29 
30 //_______________________________________________
31 // own includes
32 #include <threadhelp/readguard.hxx>
33 #include <threadhelp/writeguard.hxx>
34 #include <services.h>
35 
36 //_______________________________________________
37 // interface includes
38 #include <com/sun/star/frame/XFrame.hpp>
39 #include <com/sun/star/frame/XController.hpp>
40 #include <com/sun/star/frame/XModel.hpp>
41 #include <com/sun/star/frame/XModule.hpp>
42 #include <comphelper/configurationhelper.hxx>
43 #include <comphelper/sequenceashashmap.hxx>
44 #include <comphelper/sequenceasvector.hxx>
45 #include <comphelper/enumhelper.hxx>
46 
47 //_______________________________________________
48 // other includes
49 #include <rtl/logfile.hxx>
50 
51 namespace framework
52 {
53 
54 static const ::rtl::OUString CFGPATH_FACTORIES     = ::rtl::OUString::createFromAscii("/org.openoffice.Setup/Office/Factories");
55 static const ::rtl::OUString MODULEPROP_IDENTIFIER = ::rtl::OUString::createFromAscii("ooSetupFactoryModuleIdentifier" );
56 
57 /*-----------------------------------------------
58     04.12.2003 09:32
59 -----------------------------------------------*/
DEFINE_XINTERFACE_7(ModuleManager,OWeakObject,DIRECT_INTERFACE (css::lang::XTypeProvider),DIRECT_INTERFACE (css::lang::XServiceInfo),DIRECT_INTERFACE (css::container::XNameReplace),DIRECT_INTERFACE (css::container::XNameAccess),DIRECT_INTERFACE (css::container::XElementAccess),DIRECT_INTERFACE (css::container::XContainerQuery),DIRECT_INTERFACE (css::frame::XModuleManager))60 DEFINE_XINTERFACE_7(ModuleManager                                    ,
61                     OWeakObject                                      ,
62                     DIRECT_INTERFACE(css::lang::XTypeProvider       ),
63                     DIRECT_INTERFACE(css::lang::XServiceInfo        ),
64                     DIRECT_INTERFACE(css::container::XNameReplace   ),
65                     DIRECT_INTERFACE(css::container::XNameAccess    ),
66                     DIRECT_INTERFACE(css::container::XElementAccess ),
67                     DIRECT_INTERFACE(css::container::XContainerQuery),
68                     DIRECT_INTERFACE(css::frame::XModuleManager     ))
69 
70 /*-----------------------------------------------
71     04.12.2003 09:32
72 -----------------------------------------------*/
73 DEFINE_XTYPEPROVIDER_7(ModuleManager                  ,
74                        css::lang::XTypeProvider       ,
75                        css::lang::XServiceInfo        ,
76                        css::container::XNameReplace   ,
77                        css::container::XNameAccess    ,
78                        css::container::XElementAccess ,
79                        css::container::XContainerQuery,
80                        css::frame::XModuleManager     )
81 
82 /*-----------------------------------------------
83     04.12.2003 09:35
84 -----------------------------------------------*/
85 DEFINE_XSERVICEINFO_ONEINSTANCESERVICE(ModuleManager                   ,
86                                        ::cppu::OWeakObject             ,
87                                        SERVICENAME_MODULEMANAGER       ,
88                                        IMPLEMENTATIONNAME_MODULEMANAGER)
89 
90 /*-----------------------------------------------
91     04.12.2003 09:35
92 -----------------------------------------------*/
93 DEFINE_INIT_SERVICE(
94                     ModuleManager,
95                     {
96                         /*Attention
97                             I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance()
98                             to create a new instance of this class by our own supported service factory.
99                             see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations!
100                         */
101                     }
102                    )
103 
104 /*-----------------------------------------------
105     04.12.2003 09:30
106 -----------------------------------------------*/
107 ModuleManager::ModuleManager(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR)
108     : ThreadHelpBase(     )
109     , m_xSMGR       (xSMGR)
110 {
111 }
112 
113 /*-----------------------------------------------
114     10.12.2003 11:59
115 -----------------------------------------------*/
~ModuleManager()116 ModuleManager::~ModuleManager()
117 {
118     if (m_xCFG.is())
119         m_xCFG.clear();
120 }
121 
122 /*-----------------------------------------------
123     10.12.2003 11:02
124 -----------------------------------------------*/
identify(const css::uno::Reference<css::uno::XInterface> & xModule)125 ::rtl::OUString SAL_CALL ModuleManager::identify(const css::uno::Reference< css::uno::XInterface >& xModule)
126 {
127     // valid parameter?
128     css::uno::Reference< css::frame::XFrame >      xFrame     (xModule, css::uno::UNO_QUERY);
129     css::uno::Reference< css::awt::XWindow >       xWindow    (xModule, css::uno::UNO_QUERY);
130     css::uno::Reference< css::frame::XController > xController(xModule, css::uno::UNO_QUERY);
131     css::uno::Reference< css::frame::XModel >      xModel     (xModule, css::uno::UNO_QUERY);
132 
133     if (
134         (!xFrame.is()     ) &&
135         (!xWindow.is()    ) &&
136         (!xController.is()) &&
137         (!xModel.is()     )
138        )
139     {
140         throw css::lang::IllegalArgumentException(
141                 ::rtl::OUString::createFromAscii("Given module is not a frame nor a window, controller or model."),
142                 static_cast< ::cppu::OWeakObject* >(this),
143                 1);
144     }
145 
146     if (xFrame.is())
147     {
148         xController = xFrame->getController();
149         xWindow     = xFrame->getComponentWindow();
150     }
151     if (xController.is())
152         xModel = xController->getModel();
153 
154     // modules are implemented by the deepest component in hierarchy ...
155     // Means: model -> controller -> window
156     // No fallbacks to higher components are allowed !
157     // Note : A frame provides access to module components only ... but it's not a module by himself.
158 
159     ::rtl::OUString sModule;
160     if (xModel.is())
161         sModule = implts_identify(xModel);
162     else
163     if (xController.is())
164         sModule = implts_identify(xController);
165     else
166     if (xWindow.is())
167         sModule = implts_identify(xWindow);
168 
169     if (sModule.getLength() < 1)
170         throw css::frame::UnknownModuleException(
171                 ::rtl::OUString::createFromAscii("Can't find suitable module for the given component."),
172                 static_cast< ::cppu::OWeakObject* >(this));
173 
174     return sModule;
175 }
176 
177 /*-----------------------------------------------
178     08.03.2007 09:55
179 -----------------------------------------------*/
replaceByName(const::rtl::OUString & sName,const css::uno::Any & aValue)180 void SAL_CALL ModuleManager::replaceByName(const ::rtl::OUString& sName ,
181                                            const css::uno::Any&   aValue)
182 {
183     ::comphelper::SequenceAsHashMap lProps(aValue);
184     if (lProps.empty() )
185     {
186         throw css::lang::IllegalArgumentException(
187                 ::rtl::OUString::createFromAscii("No properties given to replace part of module."),
188                 static_cast< css::container::XNameAccess* >(this),
189                 2);
190     }
191 
192     // SAFE -> ----------------------------------
193     ReadGuard aReadLock(m_aLock);
194     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
195     aReadLock.unlock();
196     // <- SAFE ----------------------------------
197 
198     // get access to the element
199     // Note: Dont use impl_getConfig() method here. Because it creates a readonly access only, further
200     // it cache it as a member of this module manager instance. If we change some props there ... but dont
201     // flush changes (because an error occurred) we will read them later. If we use a different config access
202     // we can close it without a flush ... and our read data won't be affected .-)
203     css::uno::Reference< css::uno::XInterface >         xCfg      = ::comphelper::ConfigurationHelper::openConfig(
204                                                                         xSMGR,
205                                                                         CFGPATH_FACTORIES,
206                                                                         ::comphelper::ConfigurationHelper::E_STANDARD);
207     css::uno::Reference< css::container::XNameAccess >  xModules (xCfg, css::uno::UNO_QUERY_THROW);
208     css::uno::Reference< css::container::XNameReplace > xModule  ;
209 
210     xModules->getByName(sName) >>= xModule;
211     if (!xModule.is())
212     {
213         throw css::uno::RuntimeException(
214                 ::rtl::OUString::createFromAscii("Was not able to get write access to the requested module entry inside configuration."),
215                 static_cast< css::container::XNameAccess* >(this));
216     }
217 
218     ::comphelper::SequenceAsHashMap::const_iterator pProp;
219     for (  pProp  = lProps.begin();
220            pProp != lProps.end()  ;
221          ++pProp                  )
222     {
223         const ::rtl::OUString& sPropName  = pProp->first;
224         const css::uno::Any&   aPropValue = pProp->second;
225 
226         // let "NoSuchElementException" out ! We support the same API ...
227         // and without a flush() at the end all changed data before will be ignored !
228         xModule->replaceByName(sPropName, aPropValue);
229     }
230 
231     ::comphelper::ConfigurationHelper::flush(xCfg);
232 }
233 
234 /*-----------------------------------------------
235     10.12.2003 12:05
236 -----------------------------------------------*/
getByName(const::rtl::OUString & sName)237 css::uno::Any SAL_CALL ModuleManager::getByName(const ::rtl::OUString& sName)
238 {
239     // get access to the element
240     css::uno::Reference< css::container::XNameAccess > xCFG = implts_getConfig();
241     css::uno::Reference< css::container::XNameAccess > xModule;
242     xCFG->getByName(sName) >>= xModule;
243     if (!xModule.is())
244     {
245         throw css::uno::RuntimeException(
246                 ::rtl::OUString::createFromAscii("Was not able to get write access to the requested module entry inside configuration."),
247                 static_cast< css::container::XNameAccess* >(this));
248     }
249 
250     // convert it to seq< PropertyValue >
251     const css::uno::Sequence< ::rtl::OUString > lPropNames = xModule->getElementNames();
252           ::comphelper::SequenceAsHashMap       lProps     ;
253           sal_Int32                             c          = lPropNames.getLength();
254           sal_Int32                             i          = 0;
255 
256     lProps[MODULEPROP_IDENTIFIER] <<= sName;
257     for (i=0; i<c; ++i)
258     {
259         const ::rtl::OUString& sPropName         = lPropNames[i];
260                                lProps[sPropName] = xModule->getByName(sPropName);
261     }
262 
263     return css::uno::makeAny(lProps.getAsConstPropertyValueList());
264 }
265 
266 /*-----------------------------------------------
267     10.12.2003 11:58
268 -----------------------------------------------*/
getElementNames()269 css::uno::Sequence< ::rtl::OUString > SAL_CALL ModuleManager::getElementNames()
270 {
271     css::uno::Reference< css::container::XNameAccess > xCFG = implts_getConfig();
272     return xCFG->getElementNames();
273 }
274 
275 /*-----------------------------------------------
276     10.12.2003 11:57
277 -----------------------------------------------*/
hasByName(const::rtl::OUString & sName)278 sal_Bool SAL_CALL ModuleManager::hasByName(const ::rtl::OUString& sName)
279 {
280     css::uno::Reference< css::container::XNameAccess > xCFG = implts_getConfig();
281     return xCFG->hasByName(sName);
282 }
283 
284 /*-----------------------------------------------
285     10.12.2003 11:35
286 -----------------------------------------------*/
getElementType()287 css::uno::Type SAL_CALL ModuleManager::getElementType()
288 {
289     return ::getCppuType((const css::uno::Sequence< css::beans::PropertyValue >*)0);
290 }
291 
292 /*-----------------------------------------------
293     10.12.2003 11:56
294 -----------------------------------------------*/
hasElements()295 sal_Bool SAL_CALL ModuleManager::hasElements()
296 {
297     css::uno::Reference< css::container::XNameAccess > xCFG = implts_getConfig();
298     return xCFG->hasElements();
299 }
300 
301 /*-----------------------------------------------
302     07.03.2007 12:55
303 -----------------------------------------------*/
createSubSetEnumerationByQuery(const::rtl::OUString &)304 css::uno::Reference< css::container::XEnumeration > SAL_CALL ModuleManager::createSubSetEnumerationByQuery(const ::rtl::OUString&)
305 {
306     return css::uno::Reference< css::container::XEnumeration >();
307 }
308 
309 /*-----------------------------------------------
310     07.03.2007 12:55
311 -----------------------------------------------*/
createSubSetEnumerationByProperties(const css::uno::Sequence<css::beans::NamedValue> & lProperties)312 css::uno::Reference< css::container::XEnumeration > SAL_CALL ModuleManager::createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties)
313 {
314     ::comphelper::SequenceAsHashMap                 lSearchProps (lProperties);
315     css::uno::Sequence< ::rtl::OUString >           lModules     = getElementNames();
316     sal_Int32                                       c            = lModules.getLength();
317     sal_Int32                                       i            = 0;
318     ::comphelper::SequenceAsVector< css::uno::Any > lResult      ;
319 
320     for (i=0; i<c; ++i)
321     {
322         try
323         {
324             const ::rtl::OUString&                sModule      = lModules[i];
325                   ::comphelper::SequenceAsHashMap lModuleProps = getByName(sModule);
326 
327             if (lModuleProps.match(lSearchProps))
328                 lResult.push_back(css::uno::makeAny(lModuleProps.getAsConstPropertyValueList()));
329         }
330         catch(const css::uno::Exception&)
331             {}
332     }
333 
334     ::comphelper::OAnyEnumeration*                      pEnum = new ::comphelper::OAnyEnumeration(lResult.getAsConstList());
335     css::uno::Reference< css::container::XEnumeration > xEnum(static_cast< css::container::XEnumeration* >(pEnum), css::uno::UNO_QUERY_THROW);
336     return xEnum;
337 }
338 
339 /*-----------------------------------------------
340     14.12.2003 09:45
341 -----------------------------------------------*/
implts_getConfig()342 css::uno::Reference< css::container::XNameAccess > ModuleManager::implts_getConfig()
343 {
344     // SAFE -> ----------------------------------
345     ReadGuard aReadLock(m_aLock);
346     if (m_xCFG.is())
347         return m_xCFG;
348     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
349     aReadLock.unlock();
350     // <- SAFE ----------------------------------
351 
352     css::uno::Reference< css::uno::XInterface > xCfg;
353     try
354     {
355         xCfg = ::comphelper::ConfigurationHelper::openConfig(
356                     xSMGR,
357                     CFGPATH_FACTORIES,
358                     ::comphelper::ConfigurationHelper::E_READONLY);
359     }
360     catch(const css::uno::RuntimeException& exRun)
361         { throw exRun; }
362     catch(const css::uno::Exception&)
363         { xCfg.clear(); }
364 
365     // SAFE -> ----------------------------------
366     WriteGuard aWriteLock(m_aLock);
367     m_xCFG = css::uno::Reference< css::container::XNameAccess >(xCfg, css::uno::UNO_QUERY_THROW);
368     return m_xCFG;
369     // <- SAFE ----------------------------------
370 }
371 
372 /*-----------------------------------------------
373     30.01.2004 07:54
374 -----------------------------------------------*/
implts_identify(const css::uno::Reference<css::uno::XInterface> & xComponent)375 ::rtl::OUString ModuleManager::implts_identify(const css::uno::Reference< css::uno::XInterface >& xComponent)
376 {
377     // Search for an optional (!) interface XModule first.
378     // It's used to overrule an existing service name. Used e.g. by our database form designer
379     // which uses a writer module internally.
380     css::uno::Reference< css::frame::XModule > xModule(xComponent, css::uno::UNO_QUERY);
381     if (xModule.is())
382         return xModule->getIdentifier();
383 
384     // detect modules in a generic way ...
385     // comparing service names with configured entries ...
386     css::uno::Reference< css::lang::XServiceInfo > xInfo(xComponent, css::uno::UNO_QUERY);
387     if (!xInfo.is())
388         return ::rtl::OUString();
389 
390     const css::uno::Sequence< ::rtl::OUString > lKnownModules = getElementNames();
391     const ::rtl::OUString*                      pKnownModules = lKnownModules.getConstArray();
392           sal_Int32                             c             = lKnownModules.getLength();
393           sal_Int32                             i             = 0;
394 
395     for (i=0; i<c; ++i)
396     {
397         if (xInfo->supportsService(pKnownModules[i]))
398             return pKnownModules[i];
399     }
400 
401     return ::rtl::OUString();
402 }
403 
404 } // namespace framework
405