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 #include "precompiled_sd.hxx"
29 
30 #include "framework/ModuleController.hxx"
31 
32 #include "tools/ConfigurationAccess.hxx"
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/stl_types.hxx>
35 #include <boost/bind.hpp>
36 #include <hash_map>
37 
38 #include <tools/diagnose_ex.h>
39 
40 using namespace ::com::sun::star;
41 using namespace ::com::sun::star::uno;
42 using namespace ::com::sun::star::drawing::framework;
43 using ::rtl::OUString;
44 using ::sd::tools::ConfigurationAccess;
45 
46 #undef VERBOSE
47 //#define VERBOSE 2
48 
49 namespace sd { namespace framework {
50 
51 static const sal_uInt32 snFactoryPropertyCount (2);
52 static const sal_uInt32 snStartupPropertyCount (1);
53 
54 
55 
56 
57 class ModuleController::ResourceToFactoryMap
58     : public ::std::hash_map<
59     rtl::OUString,
60     rtl::OUString,
61     ::comphelper::UStringHash,
62     ::comphelper::UStringEqual>
63 {
64 public:
65     ResourceToFactoryMap (void) {}
66 };
67 
68 
69 class ModuleController::LoadedFactoryContainer
70     : public ::std::hash_map<
71     rtl::OUString,
72     WeakReference<XInterface>,
73     ::comphelper::UStringHash,
74     ::comphelper::UStringEqual>
75 {
76 public:
77     LoadedFactoryContainer (void) {}
78 };
79 
80 
81 
82 
83 
84 Reference<XInterface> SAL_CALL ModuleController_createInstance (
85     const Reference<XComponentContext>& rxContext)
86 {
87     return Reference<XInterface>(ModuleController::CreateInstance(rxContext), UNO_QUERY);
88 }
89 
90 
91 
92 
93 ::rtl::OUString ModuleController_getImplementationName (void) throw(RuntimeException)
94 {
95     return ::rtl::OUString(
96         RTL_CONSTASCII_USTRINGPARAM("com.sun.star.comp.Draw.framework.module.ModuleController"));
97 }
98 
99 
100 
101 
102 Sequence<rtl::OUString> SAL_CALL ModuleController_getSupportedServiceNames (void)
103     throw (RuntimeException)
104 {
105 	static const ::rtl::OUString sServiceName(
106         ::rtl::OUString::createFromAscii("com.sun.star.drawing.framework.ModuleController"));
107 	return Sequence<rtl::OUString>(&sServiceName, 1);
108 }
109 
110 
111 
112 
113 //===== ModuleController ======================================================
114 
115 Reference<XModuleController> ModuleController::CreateInstance (
116     const Reference<XComponentContext>& rxContext)
117 {
118     return new ModuleController(rxContext);
119 }
120 
121 
122 
123 
124 ModuleController::ModuleController (const Reference<XComponentContext>& rxContext) throw()
125     : ModuleControllerInterfaceBase(MutexOwner::maMutex),
126       mxController(),
127       mpResourceToFactoryMap(new ResourceToFactoryMap()),
128       mpLoadedFactories(new LoadedFactoryContainer())
129 {
130     (void)rxContext;
131     LoadFactories(rxContext);
132 }
133 
134 
135 
136 
137 ModuleController::~ModuleController (void) throw()
138 {
139 }
140 
141 
142 
143 
144 void SAL_CALL ModuleController::disposing (void)
145 {
146     // Break the cyclic reference back to DrawController object
147     mpLoadedFactories.reset();
148     mpResourceToFactoryMap.reset();
149     mxController.clear();
150 }
151 
152 
153 
154 
155 void ModuleController::LoadFactories (const Reference<XComponentContext>& rxContext)
156 {
157     try
158     {
159         ConfigurationAccess aConfiguration (
160             rxContext,
161             OUString::createFromAscii("/org.openoffice.Office.Impress/"),
162             ConfigurationAccess::READ_ONLY);
163         Reference<container::XNameAccess> xFactories (
164             aConfiguration.GetConfigurationNode(
165                 OUString::createFromAscii("MultiPaneGUI/Framework/ResourceFactories")),
166             UNO_QUERY);
167         ::std::vector<rtl::OUString> aProperties (snFactoryPropertyCount);
168         aProperties[0] = OUString::createFromAscii("ServiceName");
169         aProperties[1] = OUString::createFromAscii("ResourceList");
170         ConfigurationAccess::ForAll(
171             xFactories,
172             aProperties,
173             ::boost::bind(&ModuleController::ProcessFactory, this, _2));
174     }
175     catch (Exception&)
176     {
177         DBG_UNHANDLED_EXCEPTION();
178     }
179 }
180 
181 
182 
183 
184 void ModuleController::ProcessFactory (const ::std::vector<Any>& rValues)
185 {
186     OSL_ASSERT(rValues.size() == snFactoryPropertyCount);
187 
188     // Get the service name of the factory.
189     rtl::OUString sServiceName;
190     rValues[0] >>= sServiceName;
191 
192     // Get all resource URLs that are created by the factory.
193     Reference<container::XNameAccess> xResources (rValues[1], UNO_QUERY);
194     ::std::vector<rtl::OUString> aURLs;
195     tools::ConfigurationAccess::FillList(
196         xResources,
197         OUString::createFromAscii("URL"),
198         aURLs);
199 
200 #if defined VERBOSE && VERBOSE>0
201     OSL_TRACE("ModuleController::adding factory %s",
202         OUStringToOString(sServiceName, RTL_TEXTENCODING_UTF8).getStr());
203 #endif
204 
205     // Add the resource URLs to the map.
206     ::std::vector<rtl::OUString>::const_iterator iResource;
207     for (iResource=aURLs.begin(); iResource!=aURLs.end(); ++iResource)
208     {
209         (*mpResourceToFactoryMap)[*iResource] = sServiceName;
210 #if defined VERBOSE && VERBOSE>1
211         OSL_TRACE("    %s",
212             OUStringToOString(*iResource, RTL_TEXTENCODING_UTF8).getStr());
213 #endif
214     }
215 }
216 
217 
218 
219 
220 void ModuleController::InstantiateStartupServices (void)
221 {
222     try
223     {
224         tools::ConfigurationAccess aConfiguration (
225             OUString::createFromAscii("/org.openoffice.Office.Impress/"),
226             tools::ConfigurationAccess::READ_ONLY);
227         Reference<container::XNameAccess> xFactories (
228             aConfiguration.GetConfigurationNode(
229                 OUString::createFromAscii("MultiPaneGUI/Framework/StartupServices")),
230             UNO_QUERY);
231         ::std::vector<rtl::OUString> aProperties (snStartupPropertyCount);
232         aProperties[0] = OUString::createFromAscii("ServiceName");
233         tools::ConfigurationAccess::ForAll(
234             xFactories,
235             aProperties,
236             ::boost::bind(&ModuleController::ProcessStartupService, this, _2));
237     }
238     catch (Exception&)
239     {
240         OSL_TRACE("ERROR in ModuleController::InstantiateStartupServices");
241     }
242 }
243 
244 
245 
246 
247 void ModuleController::ProcessStartupService (const ::std::vector<Any>& rValues)
248 {
249     OSL_ASSERT(rValues.size() == snStartupPropertyCount);
250 
251     try
252     {
253         // Get the service name of the startup service.
254         rtl::OUString sServiceName;
255         rValues[0] >>= sServiceName;
256 
257         // Instantiate service.
258         Reference<lang::XMultiServiceFactory> xGlobalFactory (
259             ::comphelper::getProcessServiceFactory(), UNO_QUERY);
260         if (xGlobalFactory.is())
261         {
262             // Create the startup service.
263             Sequence<Any> aArguments(1);
264             aArguments[0] <<= mxController;
265             // Note that when the new object will be destroyed at the end of
266             // this scope when it does not register itself anywhere.
267             // Typically it will add itself as ConfigurationChangeListener
268             // at the configuration controller.
269             xGlobalFactory->createInstanceWithArguments(sServiceName, aArguments);
270 
271 #if defined VERBOSE && VERBOSE>0
272             OSL_TRACE("ModuleController::created startup service %s",
273                 OUStringToOString(sServiceName, RTL_TEXTENCODING_UTF8).getStr());
274 #endif
275         }
276     }
277     catch (Exception&)
278     {
279         OSL_TRACE("ERROR in ModuleController::ProcessStartupServices");
280     }
281 }
282 
283 
284 
285 
286 //----- XModuleController -----------------------------------------------------
287 
288 void SAL_CALL ModuleController::requestResource (const OUString& rsResourceURL)
289     throw (RuntimeException)
290 {
291     ResourceToFactoryMap::const_iterator iFactory (mpResourceToFactoryMap->find(rsResourceURL));
292     if (iFactory != mpResourceToFactoryMap->end())
293     {
294         // Check that the factory has already been loaded and not been
295         // destroyed in the meantime.
296         Reference<XInterface> xFactory;
297         LoadedFactoryContainer::const_iterator iLoadedFactory (
298             mpLoadedFactories->find(iFactory->second));
299         if (iLoadedFactory != mpLoadedFactories->end())
300             xFactory = Reference<XInterface>(iLoadedFactory->second, UNO_QUERY);
301         if ( ! xFactory.is())
302         {
303             // Create a new instance of the factory.
304             Reference<lang::XMultiServiceFactory> xGlobalFactory (
305                 ::comphelper::getProcessServiceFactory(), UNO_QUERY);
306             if (xGlobalFactory.is())
307             {
308                 // Create the factory service.
309                 Sequence<Any> aArguments(1);
310                 aArguments[0] <<= mxController;
311                 xFactory = xGlobalFactory->createInstanceWithArguments(
312                     iFactory->second,
313                     aArguments);
314 
315                 // Remember that this factory has been instanced.
316                 (*mpLoadedFactories)[iFactory->second] = xFactory;
317             }
318         }
319     }
320 }
321 
322 
323 
324 
325 //----- XInitialization -------------------------------------------------------
326 
327 void SAL_CALL ModuleController::initialize (const Sequence<Any>& aArguments)
328     throw (Exception, RuntimeException)
329 {
330     if (aArguments.getLength() > 0)
331     {
332         try
333         {
334             // Get the XController from the first argument.
335             mxController = Reference<frame::XController>(aArguments[0], UNO_QUERY_THROW);
336 
337             InstantiateStartupServices();
338         }
339         catch (RuntimeException&)
340         {}
341     }
342 }
343 
344 
345 } } // end of namespace sd::framework
346