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 -----------------------------------------------*/
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 -----------------------------------------------*/
116 ModuleManager::~ModuleManager()
117 {
118     if (m_xCFG.is())
119         m_xCFG.clear();
120 }
121 
122 /*-----------------------------------------------
123     10.12.2003 11:02
124 -----------------------------------------------*/
125 ::rtl::OUString SAL_CALL ModuleManager::identify(const css::uno::Reference< css::uno::XInterface >& xModule)
126     throw(css::lang::IllegalArgumentException,
127           css::frame::UnknownModuleException,
128           css::uno::RuntimeException         )
129 {
130     // valid parameter?
131     css::uno::Reference< css::frame::XFrame >      xFrame     (xModule, css::uno::UNO_QUERY);
132     css::uno::Reference< css::awt::XWindow >       xWindow    (xModule, css::uno::UNO_QUERY);
133     css::uno::Reference< css::frame::XController > xController(xModule, css::uno::UNO_QUERY);
134     css::uno::Reference< css::frame::XModel >      xModel     (xModule, css::uno::UNO_QUERY);
135 
136     if (
137         (!xFrame.is()     ) &&
138         (!xWindow.is()    ) &&
139         (!xController.is()) &&
140         (!xModel.is()     )
141        )
142     {
143         throw css::lang::IllegalArgumentException(
144                 ::rtl::OUString::createFromAscii("Given module is not a frame nor a window, controller or model."),
145                 static_cast< ::cppu::OWeakObject* >(this),
146                 1);
147     }
148 
149 	if (xFrame.is())
150     {
151 		xController = xFrame->getController();
152         xWindow     = xFrame->getComponentWindow();
153     }
154     if (xController.is())
155         xModel = xController->getModel();
156 
157     // modules are implemented by the deepest component in hierarchy ...
158     // Means: model -> controller -> window
159     // No fallbacks to higher components are allowed !
160     // Note : A frame provides access to module components only ... but it's not a module by himself.
161 
162     ::rtl::OUString sModule;
163     if (xModel.is())
164         sModule = implts_identify(xModel);
165     else
166     if (xController.is())
167         sModule = implts_identify(xController);
168     else
169     if (xWindow.is())
170         sModule = implts_identify(xWindow);
171 
172     if (sModule.getLength() < 1)
173         throw css::frame::UnknownModuleException(
174                 ::rtl::OUString::createFromAscii("Cant find suitable module for the given component."),
175                 static_cast< ::cppu::OWeakObject* >(this));
176 
177     return sModule;
178 }
179 
180 /*-----------------------------------------------
181     08.03.2007 09:55
182 -----------------------------------------------*/
183 void SAL_CALL ModuleManager::replaceByName(const ::rtl::OUString& sName ,
184                                            const css::uno::Any&   aValue)
185     throw (css::lang::IllegalArgumentException   ,
186            css::container::NoSuchElementException,
187            css::lang::WrappedTargetException     ,
188            css::uno::RuntimeException            )
189 {
190     ::comphelper::SequenceAsHashMap lProps(aValue);
191     if (lProps.empty() )
192     {
193         throw css::lang::IllegalArgumentException(
194                 ::rtl::OUString::createFromAscii("No properties given to replace part of module."),
195                 static_cast< css::container::XNameAccess* >(this),
196                 2);
197     }
198 
199     // SAFE -> ----------------------------------
200     ReadGuard aReadLock(m_aLock);
201     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
202     aReadLock.unlock();
203     // <- SAFE ----------------------------------
204 
205     // get access to the element
206     // Note: Dont use impl_getConfig() method here. Because it creates a readonly access only, further
207     // it cache it as a member of this module manager instance. If we change some props there ... but dont
208     // flush changes (because an error occured) we will read them later. If we use a different config access
209     // we can close it without a flush ... and our read data wont be affected .-)
210     css::uno::Reference< css::uno::XInterface >         xCfg      = ::comphelper::ConfigurationHelper::openConfig(
211                                                                         xSMGR,
212                                                                         CFGPATH_FACTORIES,
213                                                                         ::comphelper::ConfigurationHelper::E_STANDARD);
214     css::uno::Reference< css::container::XNameAccess >  xModules (xCfg, css::uno::UNO_QUERY_THROW);
215     css::uno::Reference< css::container::XNameReplace > xModule  ;
216 
217     xModules->getByName(sName) >>= xModule;
218     if (!xModule.is())
219     {
220         throw css::uno::RuntimeException(
221                 ::rtl::OUString::createFromAscii("Was not able to get write access to the requested module entry inside configuration."),
222                 static_cast< css::container::XNameAccess* >(this));
223     }
224 
225     ::comphelper::SequenceAsHashMap::const_iterator pProp;
226     for (  pProp  = lProps.begin();
227            pProp != lProps.end()  ;
228          ++pProp                  )
229     {
230         const ::rtl::OUString& sPropName  = pProp->first;
231         const css::uno::Any&   aPropValue = pProp->second;
232 
233         // let "NoSuchElementException" out ! We support the same API ...
234         // and without a flush() at the end all changed data before will be ignored !
235         xModule->replaceByName(sPropName, aPropValue);
236     }
237 
238     ::comphelper::ConfigurationHelper::flush(xCfg);
239 }
240 
241 /*-----------------------------------------------
242     10.12.2003 12:05
243 -----------------------------------------------*/
244 css::uno::Any SAL_CALL ModuleManager::getByName(const ::rtl::OUString& sName)
245     throw(css::container::NoSuchElementException,
246           css::lang::WrappedTargetException     ,
247           css::uno::RuntimeException            )
248 {
249     // get access to the element
250     css::uno::Reference< css::container::XNameAccess > xCFG = implts_getConfig();
251     css::uno::Reference< css::container::XNameAccess > xModule;
252     xCFG->getByName(sName) >>= xModule;
253     if (!xModule.is())
254     {
255         throw css::uno::RuntimeException(
256                 ::rtl::OUString::createFromAscii("Was not able to get write access to the requested module entry inside configuration."),
257                 static_cast< css::container::XNameAccess* >(this));
258     }
259 
260     // convert it to seq< PropertyValue >
261     const css::uno::Sequence< ::rtl::OUString > lPropNames = xModule->getElementNames();
262           ::comphelper::SequenceAsHashMap       lProps     ;
263           sal_Int32                             c          = lPropNames.getLength();
264           sal_Int32                             i          = 0;
265 
266     lProps[MODULEPROP_IDENTIFIER] <<= sName;
267     for (i=0; i<c; ++i)
268     {
269         const ::rtl::OUString& sPropName         = lPropNames[i];
270                                lProps[sPropName] = xModule->getByName(sPropName);
271     }
272 
273     return css::uno::makeAny(lProps.getAsConstPropertyValueList());
274 }
275 
276 /*-----------------------------------------------
277     10.12.2003 11:58
278 -----------------------------------------------*/
279 css::uno::Sequence< ::rtl::OUString > SAL_CALL ModuleManager::getElementNames()
280     throw(css::uno::RuntimeException)
281 {
282     css::uno::Reference< css::container::XNameAccess > xCFG = implts_getConfig();
283     return xCFG->getElementNames();
284 }
285 
286 /*-----------------------------------------------
287     10.12.2003 11:57
288 -----------------------------------------------*/
289 sal_Bool SAL_CALL ModuleManager::hasByName(const ::rtl::OUString& sName)
290     throw(css::uno::RuntimeException)
291 {
292     css::uno::Reference< css::container::XNameAccess > xCFG = implts_getConfig();
293     return xCFG->hasByName(sName);
294 }
295 
296 /*-----------------------------------------------
297     10.12.2003 11:35
298 -----------------------------------------------*/
299 css::uno::Type SAL_CALL ModuleManager::getElementType()
300     throw(css::uno::RuntimeException)
301 {
302     return ::getCppuType((const css::uno::Sequence< css::beans::PropertyValue >*)0);
303 }
304 
305 /*-----------------------------------------------
306     10.12.2003 11:56
307 -----------------------------------------------*/
308 sal_Bool SAL_CALL ModuleManager::hasElements()
309     throw(css::uno::RuntimeException)
310 {
311     css::uno::Reference< css::container::XNameAccess > xCFG = implts_getConfig();
312     return xCFG->hasElements();
313 }
314 
315 /*-----------------------------------------------
316     07.03.2007 12:55
317 -----------------------------------------------*/
318 css::uno::Reference< css::container::XEnumeration > SAL_CALL ModuleManager::createSubSetEnumerationByQuery(const ::rtl::OUString&)
319     throw(css::uno::RuntimeException)
320 {
321     return css::uno::Reference< css::container::XEnumeration >();
322 }
323 
324 /*-----------------------------------------------
325     07.03.2007 12:55
326 -----------------------------------------------*/
327 css::uno::Reference< css::container::XEnumeration > SAL_CALL ModuleManager::createSubSetEnumerationByProperties(const css::uno::Sequence< css::beans::NamedValue >& lProperties)
328     throw(css::uno::RuntimeException)
329 {
330     ::comphelper::SequenceAsHashMap                 lSearchProps (lProperties);
331     css::uno::Sequence< ::rtl::OUString >           lModules     = getElementNames();
332     sal_Int32                                       c            = lModules.getLength();
333     sal_Int32                                       i            = 0;
334     ::comphelper::SequenceAsVector< css::uno::Any > lResult      ;
335 
336     for (i=0; i<c; ++i)
337     {
338         try
339         {
340             const ::rtl::OUString&                sModule      = lModules[i];
341                   ::comphelper::SequenceAsHashMap lModuleProps = getByName(sModule);
342 
343             if (lModuleProps.match(lSearchProps))
344                 lResult.push_back(css::uno::makeAny(lModuleProps.getAsConstPropertyValueList()));
345         }
346         catch(const css::uno::Exception&)
347             {}
348     }
349 
350     ::comphelper::OAnyEnumeration*                      pEnum = new ::comphelper::OAnyEnumeration(lResult.getAsConstList());
351     css::uno::Reference< css::container::XEnumeration > xEnum(static_cast< css::container::XEnumeration* >(pEnum), css::uno::UNO_QUERY_THROW);
352     return xEnum;
353 }
354 
355 /*-----------------------------------------------
356     14.12.2003 09:45
357 -----------------------------------------------*/
358 css::uno::Reference< css::container::XNameAccess > ModuleManager::implts_getConfig()
359     throw(css::uno::RuntimeException)
360 {
361     // SAFE -> ----------------------------------
362     ReadGuard aReadLock(m_aLock);
363     if (m_xCFG.is())
364         return m_xCFG;
365     css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR;
366     aReadLock.unlock();
367     // <- SAFE ----------------------------------
368 
369     css::uno::Reference< css::uno::XInterface > xCfg;
370     try
371     {
372         xCfg = ::comphelper::ConfigurationHelper::openConfig(
373                     xSMGR,
374                     CFGPATH_FACTORIES,
375                     ::comphelper::ConfigurationHelper::E_READONLY);
376     }
377     catch(const css::uno::RuntimeException& exRun)
378         { throw exRun; }
379     catch(const css::uno::Exception&)
380         { xCfg.clear(); }
381 
382     // SAFE -> ----------------------------------
383     WriteGuard aWriteLock(m_aLock);
384     m_xCFG = css::uno::Reference< css::container::XNameAccess >(xCfg, css::uno::UNO_QUERY_THROW);
385     return m_xCFG;
386     // <- SAFE ----------------------------------
387 }
388 
389 /*-----------------------------------------------
390     30.01.2004 07:54
391 -----------------------------------------------*/
392 ::rtl::OUString ModuleManager::implts_identify(const css::uno::Reference< css::uno::XInterface >& xComponent)
393 {
394     // Search for an optional (!) interface XModule first.
395     // Its used to overrule an existing service name. Used e.g. by our database form designer
396     // which uses a writer module internaly.
397     css::uno::Reference< css::frame::XModule > xModule(xComponent, css::uno::UNO_QUERY);
398     if (xModule.is())
399         return xModule->getIdentifier();
400 
401     // detect modules in a generic way ...
402     // comparing service names with configured entries ...
403     css::uno::Reference< css::lang::XServiceInfo > xInfo(xComponent, css::uno::UNO_QUERY);
404     if (!xInfo.is())
405         return ::rtl::OUString();
406 
407     const css::uno::Sequence< ::rtl::OUString > lKnownModules = getElementNames();
408     const ::rtl::OUString*                      pKnownModules = lKnownModules.getConstArray();
409           sal_Int32                             c             = lKnownModules.getLength();
410           sal_Int32                             i             = 0;
411 
412     for (i=0; i<c; ++i)
413     {
414         if (xInfo->supportsService(pKnownModules[i]))
415             return pKnownModules[i];
416     }
417 
418     return ::rtl::OUString();
419 }
420 
421 } // namespace framework
422