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