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