Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "ConfigurationUpdater.hxx"
31 : : #include "ConfigurationTracer.hxx"
32 : : #include "ConfigurationClassifier.hxx"
33 : : #include "ConfigurationControllerBroadcaster.hxx"
34 : : #include "framework/Configuration.hxx"
35 : : #include "framework/FrameworkHelper.hxx"
36 : :
37 : : #include <comphelper/scopeguard.hxx>
38 : : #include <tools/diagnose_ex.h>
39 : :
40 : : #include <boost/bind.hpp>
41 : :
42 : : using namespace ::com::sun::star;
43 : : using namespace ::com::sun::star::uno;
44 : : using namespace ::com::sun::star::drawing::framework;
45 : : using ::sd::framework::FrameworkHelper;
46 : : using ::rtl::OUString;
47 : : using ::std::vector;
48 : :
49 : : namespace {
50 : : static const sal_Int32 snShortTimeout (100);
51 : : static const sal_Int32 snNormalTimeout (1000);
52 : : static const sal_Int32 snLongTimeout (10000);
53 : : static const sal_Int32 snShortTimeoutCountThreshold (1);
54 : : static const sal_Int32 snNormalTimeoutCountThreshold (5);
55 : : }
56 : :
57 : : namespace sd { namespace framework {
58 : :
59 : :
60 : : //===== ConfigurationUpdaterLock ==============================================
61 : :
62 : : class ConfigurationUpdaterLock
63 : : {
64 : : public:
65 : 325 : ConfigurationUpdaterLock (ConfigurationUpdater& rUpdater)
66 : 325 : : mrUpdater(rUpdater) { mrUpdater.LockUpdates(); }
67 : 325 : ~ConfigurationUpdaterLock(void) { mrUpdater.UnlockUpdates(); }
68 : : private:
69 : : ConfigurationUpdater& mrUpdater;
70 : : };
71 : :
72 : :
73 : :
74 : :
75 : : //===== ConfigurationUpdater ==================================================
76 : :
77 : 130 : ConfigurationUpdater::ConfigurationUpdater (
78 : : const ::boost::shared_ptr<ConfigurationControllerBroadcaster>& rpBroadcaster,
79 : : const ::boost::shared_ptr<ConfigurationControllerResourceManager>& rpResourceManager,
80 : : const Reference<XControllerManager>& rxControllerManager)
81 : : : mxControllerManager(),
82 : : mpBroadcaster(rpBroadcaster),
83 [ + - ][ + - ]: 260 : mxCurrentConfiguration(Reference<XConfiguration>(new Configuration(NULL, false))),
[ + - ]
84 : : mxRequestedConfiguration(),
85 : : mbUpdatePending(false),
86 : : mbUpdateBeingProcessed(false),
87 : : mnLockCount(0),
88 : : maUpdateTimer(),
89 : : mnFailedUpdateCount(0),
90 [ + - ]: 390 : mpResourceManager(rpResourceManager)
[ + - + - ]
[ + - ]
91 : : {
92 : : // Prepare the timer that is started when after an update the current
93 : : // and the requested configuration differ. With the timer we try
94 : : // updates until the two configurations are the same.
95 [ + - ]: 130 : maUpdateTimer.SetTimeout(snNormalTimeout);
96 [ + - ]: 130 : maUpdateTimer.SetTimeoutHdl(LINK(this,ConfigurationUpdater,TimeoutHandler));
97 [ + - ]: 130 : SetControllerManager(rxControllerManager);
98 : 130 : }
99 : :
100 : :
101 : :
102 : :
103 [ + - ][ + - ]: 130 : ConfigurationUpdater::~ConfigurationUpdater (void)
[ + - ]
104 : : {
105 [ + - ]: 130 : maUpdateTimer.Stop();
106 : 130 : }
107 : :
108 : :
109 : :
110 : :
111 : 130 : void ConfigurationUpdater::SetControllerManager(
112 : : const Reference<XControllerManager>& rxControllerManager)
113 : : {
114 : 130 : mxControllerManager = rxControllerManager;
115 : 130 : }
116 : :
117 : :
118 : :
119 : :
120 : 523 : void ConfigurationUpdater::RequestUpdate (
121 : : const Reference<XConfiguration>& rxRequestedConfiguration)
122 : : {
123 : 523 : mxRequestedConfiguration = rxRequestedConfiguration;
124 : :
125 : : // Find out whether we really can update the configuration.
126 [ + - ]: 523 : if (IsUpdatePossible())
127 : : {
128 : : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": UpdateConfiguration start");
129 : :
130 : : // Call UpdateConfiguration while that is possible and while someone
131 : : // set mbUpdatePending to true in the middle of it.
132 : : do
133 : : {
134 : 523 : UpdateConfiguration();
135 : :
136 [ # # ][ - + ]: 523 : if (mbUpdatePending && IsUpdatePossible())
[ - + ]
137 : 523 : continue;
138 : : }
139 : : while (false);
140 : : }
141 : : else
142 : : {
143 : 0 : mbUpdatePending = true;
144 : : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": scheduling update for later");
145 : : }
146 : 523 : }
147 : :
148 : :
149 : :
150 : :
151 : 0 : Reference<XConfiguration> ConfigurationUpdater::GetCurrentConfiguration (void) const
152 : : {
153 : 0 : return mxCurrentConfiguration;
154 : : }
155 : :
156 : :
157 : :
158 : :
159 : 523 : bool ConfigurationUpdater::IsUpdatePossible (void)
160 : : {
161 : 523 : return ! mbUpdateBeingProcessed
162 : 523 : && mxControllerManager.is()
163 : : && mnLockCount==0
164 : 523 : && mxRequestedConfiguration.is()
165 [ + - + - ]: 1569 : && mxCurrentConfiguration.is();
[ + - + - ]
[ + - ]
166 : : }
167 : :
168 : :
169 : :
170 : :
171 : 523 : void ConfigurationUpdater::UpdateConfiguration (void)
172 : : {
173 : : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": UpdateConfiguration update");
174 : 523 : SetUpdateBeingProcessed(true);
175 : : comphelper::ScopeGuard aScopeGuard (
176 [ + - # # ]: 523 : ::boost::bind(&ConfigurationUpdater::SetUpdateBeingProcessed, this, false));
[ + - ]
177 : :
178 : : try
179 : : {
180 : 523 : mbUpdatePending = false;
181 : :
182 [ + - ]: 523 : CleanRequestedConfiguration();
183 [ + - ]: 523 : ConfigurationClassifier aClassifier(mxRequestedConfiguration, mxCurrentConfiguration);
184 [ + - ][ + + ]: 523 : if (aClassifier.Partition())
185 : : {
186 : : #if OSL_DEBUG_LEVEL >= 2
187 : : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationUpdater::UpdateConfiguration(");
188 : : ConfigurationTracer::TraceConfiguration(
189 : : mxRequestedConfiguration, "requested configuration");
190 : : ConfigurationTracer::TraceConfiguration(
191 : : mxCurrentConfiguration, "current configuration");
192 : : #endif
193 : : // Notify the begining of the update.
194 [ + - ]: 412 : ConfigurationChangeEvent aEvent;
195 : 412 : aEvent.Type = FrameworkHelper::msConfigurationUpdateStartEvent;
196 [ + - ]: 412 : aEvent.Configuration = mxRequestedConfiguration;
197 [ + - ]: 412 : mpBroadcaster->NotifyListeners(aEvent);
198 : :
199 : : // Do the actual update. All exceptions are caught and ignored,
200 : : // so that the the end of the update is notified always.
201 : : try
202 : : {
203 [ + - ]: 412 : if (mnLockCount == 0)
204 [ + - ]: 412 : UpdateCore(aClassifier);
205 : : }
206 [ # # ]: 0 : catch(const RuntimeException&)
207 : : {
208 : : }
209 : :
210 : : // Notify the end of the update.
211 : 412 : aEvent.Type = FrameworkHelper::msConfigurationUpdateEndEvent;
212 [ + - ]: 412 : mpBroadcaster->NotifyListeners(aEvent);
213 : :
214 [ + - ][ + - ]: 412 : CheckUpdateSuccess();
215 : : }
216 : : else
217 : : {
218 : : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": nothing to do");
219 : : #if OSL_DEBUG_LEVEL >= 2
220 : : ConfigurationTracer::TraceConfiguration(
221 : : mxRequestedConfiguration, "requested configuration");
222 : : ConfigurationTracer::TraceConfiguration(
223 : : mxCurrentConfiguration, "current configuration");
224 : : #endif
225 [ + - ][ # # ]: 523 : }
226 : : }
227 [ # # ]: 0 : catch(const RuntimeException &)
228 : : {
229 : : DBG_UNHANDLED_EXCEPTION();
230 : : }
231 : :
232 : : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationUpdater::UpdateConfiguration)");
233 [ + - ]: 523 : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": UpdateConfiguration end");
234 : 523 : }
235 : :
236 : :
237 : :
238 : :
239 : 523 : void ConfigurationUpdater::CleanRequestedConfiguration (void)
240 : : {
241 [ + - ]: 523 : if (mxControllerManager.is())
242 : : {
243 : : // Request the deactivation of pure anchors that have no child.
244 [ + - ]: 523 : vector<Reference<XResourceId> > aResourcesToDeactivate;
245 [ + - ]: 523 : CheckPureAnchors(mxRequestedConfiguration, aResourcesToDeactivate);
246 [ - + ]: 523 : if (!aResourcesToDeactivate.empty())
247 : : {
248 : : Reference<XConfigurationController> xCC (
249 [ # # ][ # # ]: 0 : mxControllerManager->getConfigurationController());
250 : 0 : vector<Reference<XResourceId> >::iterator iId;
251 [ # # ][ # # ]: 0 : for (iId=aResourcesToDeactivate.begin(); iId!=aResourcesToDeactivate.end(); ++iId)
252 [ # # ]: 0 : if (iId->is())
253 [ # # ][ # # ]: 0 : xCC->requestResourceDeactivation(*iId);
254 : 523 : }
255 : : }
256 : 523 : }
257 : :
258 : :
259 : :
260 : :
261 : 412 : void ConfigurationUpdater::CheckUpdateSuccess (void)
262 : : {
263 : : // When the two configurations differ then start the timer to call
264 : : // another update later.
265 [ + + ]: 412 : if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
266 : : {
267 [ + - ]: 130 : if (mnFailedUpdateCount <= snShortTimeoutCountThreshold)
268 : 130 : maUpdateTimer.SetTimeout(snShortTimeout);
269 [ # # ]: 0 : else if (mnFailedUpdateCount < snNormalTimeoutCountThreshold)
270 : 0 : maUpdateTimer.SetTimeout(snNormalTimeout);
271 : : else
272 : 0 : maUpdateTimer.SetTimeout(snLongTimeout);
273 : 130 : ++mnFailedUpdateCount;
274 : 130 : maUpdateTimer.Start();
275 : : }
276 : : else
277 : : {
278 : : // Update was successfull. Reset the failed update count.
279 : 282 : mnFailedUpdateCount = 0;
280 : : }
281 : 412 : }
282 : :
283 : :
284 : :
285 : :
286 : 412 : void ConfigurationUpdater::UpdateCore (const ConfigurationClassifier& rClassifier)
287 : : {
288 : : try
289 : : {
290 : : #if OSL_DEBUG_LEVEL >= 2
291 : : rClassifier.TraceResourceIdVector(
292 : : "requested but not current resources:", rClassifier.GetC1minusC2());
293 : : rClassifier.TraceResourceIdVector(
294 : : "current but not requested resources:", rClassifier.GetC2minusC1());
295 : : rClassifier.TraceResourceIdVector(
296 : : "requested and current resources:", rClassifier.GetC1andC2());
297 : : #endif
298 : :
299 : : // Updating of the sub controllers is done in two steps. In the
300 : : // first the sub controllers typically shut down resources that are
301 : : // not requested anymore. In the second the sub controllers
302 : : // typically set up resources that have been newly requested.
303 [ + - ][ + - ]: 412 : mpResourceManager->DeactivateResources(rClassifier.GetC2minusC1(), mxCurrentConfiguration);
304 [ + - ][ + - ]: 412 : mpResourceManager->ActivateResources(rClassifier.GetC1minusC2(), mxCurrentConfiguration);
305 : :
306 : : #if OSL_DEBUG_LEVEL >= 2
307 : : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": ConfigurationController::UpdateConfiguration)");
308 : : ConfigurationTracer::TraceConfiguration(
309 : : mxRequestedConfiguration, "requested configuration");
310 : : ConfigurationTracer::TraceConfiguration(
311 : : mxCurrentConfiguration, "current configuration");
312 : : #endif
313 : :
314 : : // Deactivate pure anchors that have no child.
315 [ + - ]: 412 : vector<Reference<XResourceId> > aResourcesToDeactivate;
316 [ + - ]: 412 : CheckPureAnchors(mxCurrentConfiguration, aResourcesToDeactivate);
317 [ + + ]: 412 : if (!aResourcesToDeactivate.empty())
318 [ + - ][ # # ]: 412 : mpResourceManager->DeactivateResources(aResourcesToDeactivate, mxCurrentConfiguration);
319 : : }
320 : 0 : catch(const RuntimeException&)
321 : : {
322 : : DBG_UNHANDLED_EXCEPTION();
323 : : }
324 : 412 : }
325 : :
326 : :
327 : :
328 : :
329 : 935 : void ConfigurationUpdater::CheckPureAnchors (
330 : : const Reference<XConfiguration>& rxConfiguration,
331 : : vector<Reference<XResourceId> >& rResourcesToDeactivate)
332 : : {
333 [ + - ]: 935 : if ( ! rxConfiguration.is())
334 : 935 : return;
335 : :
336 : : // Get a list of all resources in the configuration.
337 : : Sequence<Reference<XResourceId> > aResources(
338 [ + - ]: 935 : rxConfiguration->getResources(
339 [ + - ][ + - ]: 935 : NULL, OUString(), AnchorBindingMode_INDIRECT));
340 : 935 : sal_Int32 nCount (aResources.getLength());
341 : :
342 : : // Prepare the list of pure anchors that have to be deactivated.
343 : 935 : rResourcesToDeactivate.clear();
344 : :
345 : : // Iterate over the list in reverse order because when there is a chain
346 : : // of pure anchors with only the last one having no child then the whole
347 : : // list has to be deactivated.
348 : 935 : sal_Int32 nIndex (nCount-1);
349 [ + + ]: 3995 : while (nIndex >= 0)
350 : : {
351 [ + - ]: 3060 : const Reference<XResourceId> xResourceId (aResources[nIndex]);
352 : : const Reference<XResource> xResource (
353 [ + - ][ + - ]: 3060 : mpResourceManager->GetResource(xResourceId).mxResource);
354 : 3060 : bool bDeactiveCurrentResource (false);
355 : :
356 : : // Skip all resources that are no pure anchors.
357 [ + + ][ + - ]: 3060 : if (xResource.is() && xResource->isAnchorOnly())
[ + - ][ + + ]
[ + + ]
358 : : {
359 : : // When xResource is not an anchor of the the next resource in
360 : : // the list then it is the anchor of no resource at all.
361 [ - + ]: 515 : if (nIndex == nCount-1)
362 : : {
363 : : // No following anchors, deactivate this one, then remove it
364 : : // from the list.
365 : 0 : bDeactiveCurrentResource = true;
366 : : }
367 : : else
368 : : {
369 [ + - ]: 515 : const Reference<XResourceId> xPrevResourceId (aResources[nIndex+1]);
370 [ + + ][ + + ]: 1030 : if ( ! xPrevResourceId.is()
[ + - ]
371 [ + - ][ + - ]: 515 : || ! xPrevResourceId->isBoundTo(xResourceId, AnchorBindingMode_DIRECT))
372 : : {
373 : : // The previous resource (id) does not exist or is not bound to
374 : : // the current anchor.
375 : 156 : bDeactiveCurrentResource = true;
376 : 515 : }
377 : : }
378 : : }
379 : :
380 [ + + ]: 3060 : if (bDeactiveCurrentResource)
381 : : {
382 : : SAL_INFO("sd.fwk", OSL_THIS_FUNC << ": deactiving pure anchor " <<
383 : : OUStringToOString(
384 : : FrameworkHelper::ResourceIdToString(xResourceId),
385 : : RTL_TEXTENCODING_UTF8).getStr() << "because it has no children");
386 : : // Erase element from current configuration.
387 [ + + ]: 364 : for (sal_Int32 nI=nIndex; nI<nCount-2; ++nI)
388 [ + - ][ + - ]: 208 : aResources[nI] = aResources[nI+1];
[ + - ]
389 : 156 : nCount -= 1;
390 : :
391 [ + - ]: 156 : rResourcesToDeactivate.push_back(xResourceId);
392 : : }
393 : 3060 : nIndex -= 1;
394 [ + - ]: 3995 : }
395 : : }
396 : :
397 : :
398 : :
399 : :
400 : 325 : void ConfigurationUpdater::LockUpdates (void)
401 : : {
402 : 325 : ++mnLockCount;
403 : 325 : }
404 : :
405 : :
406 : :
407 : :
408 : 325 : void ConfigurationUpdater::UnlockUpdates (void)
409 : : {
410 : 325 : --mnLockCount;
411 [ + - ][ - + ]: 325 : if (mnLockCount == 0 && mbUpdatePending)
412 : : {
413 : 0 : RequestUpdate(mxRequestedConfiguration);
414 : : }
415 : 325 : }
416 : :
417 : :
418 : :
419 : :
420 : 325 : ::boost::shared_ptr<ConfigurationUpdaterLock> ConfigurationUpdater::GetLock (void)
421 : : {
422 [ + - ]: 325 : return ::boost::shared_ptr<ConfigurationUpdaterLock>(new ConfigurationUpdaterLock(*this));
423 : : }
424 : :
425 : :
426 : :
427 : :
428 : 1046 : void ConfigurationUpdater::SetUpdateBeingProcessed (bool bValue)
429 : : {
430 : 1046 : mbUpdateBeingProcessed = bValue;
431 : 1046 : }
432 : :
433 : :
434 : :
435 : :
436 : 130 : IMPL_LINK_NOARG(ConfigurationUpdater, TimeoutHandler)
437 : : {
438 : : OSL_TRACE("configuration update timer");
439 [ + - + - : 390 : if ( ! mbUpdateBeingProcessed
+ - ][ + - ]
440 : 130 : && mxCurrentConfiguration.is()
441 : 130 : && mxRequestedConfiguration.is())
442 : : {
443 [ + + ]: 130 : if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration, mxRequestedConfiguration))
444 : : {
445 : : OSL_TRACE("configurations differ, requesting update");
446 : 31 : RequestUpdate(mxRequestedConfiguration);
447 : : }
448 : : }
449 : 130 : return 0;
450 : : }
451 : :
452 : :
453 [ + - ][ + - ]: 75 : } } // end of namespace sd::framework
454 : :
455 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|