1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ConfigurationUpdater.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "precompiled_sd.hxx"
33 #include "ConfigurationUpdater.hxx"
34 #include "ConfigurationTracer.hxx"
35 #include "ConfigurationClassifier.hxx"
36 #include "ConfigurationControllerBroadcaster.hxx"
37 #include "framework/Configuration.hxx"
38 #include "framework/FrameworkHelper.hxx"
40 #include <comphelper/scopeguard.hxx>
42 #include <boost/bind.hpp>
44 using namespace ::com::sun::star
;
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::drawing::framework
;
47 using ::sd::framework::FrameworkHelper
;
48 using ::rtl::OUString
;
55 static const sal_Int32
snShortTimeout (100);
56 static const sal_Int32
snNormalTimeout (1000);
57 static const sal_Int32
snLongTimeout (10000);
58 static const sal_Int32
snShortTimeoutCountThreshold (1);
59 static const sal_Int32
snNormalTimeoutCountThreshold (5);
62 namespace sd
{ namespace framework
{
65 //===== ConfigurationUpdaterLock ==============================================
67 class ConfigurationUpdaterLock
70 ConfigurationUpdaterLock (ConfigurationUpdater
& rUpdater
)
71 : mrUpdater(rUpdater
) { mrUpdater
.LockUpdates(); }
72 ~ConfigurationUpdaterLock(void) { mrUpdater
.UnlockUpdates(); }
74 ConfigurationUpdater
& mrUpdater
;
80 //===== ConfigurationUpdater ==================================================
82 ConfigurationUpdater::ConfigurationUpdater (
83 const ::boost::shared_ptr
<ConfigurationControllerBroadcaster
>& rpBroadcaster
,
84 const ::boost::shared_ptr
<ConfigurationControllerResourceManager
>& rpResourceManager
,
85 const Reference
<XControllerManager
>& rxControllerManager
)
86 : mxControllerManager(),
87 mpBroadcaster(rpBroadcaster
),
88 mxCurrentConfiguration(Reference
<XConfiguration
>(new Configuration(NULL
, false))),
89 mxRequestedConfiguration(),
90 mbUpdatePending(false),
91 mbUpdateBeingProcessed(false),
94 mnFailedUpdateCount(0),
95 mpResourceManager(rpResourceManager
)
97 // Prepare the timer that is started when after an update the current
98 // and the requested configuration differ. With the timer we try
99 // updates until the two configurations are the same.
100 maUpdateTimer
.SetTimeout(snNormalTimeout
);
101 maUpdateTimer
.SetTimeoutHdl(LINK(this,ConfigurationUpdater
,TimeoutHandler
));
102 SetControllerManager(rxControllerManager
);
108 ConfigurationUpdater::~ConfigurationUpdater (void)
110 maUpdateTimer
.Stop();
116 void ConfigurationUpdater::SetControllerManager(
117 const Reference
<XControllerManager
>& rxControllerManager
)
119 mxControllerManager
= rxControllerManager
;
125 void ConfigurationUpdater::RequestUpdate (
126 const Reference
<XConfiguration
>& rxRequestedConfiguration
)
128 mxRequestedConfiguration
= rxRequestedConfiguration
;
130 // Find out whether we really can update the configuration.
131 if (IsUpdatePossible())
133 #if defined VERBOSE && VERBOSE>=1
134 OSL_TRACE("UpdateConfiguration start\n");
137 // Call UpdateConfiguration while that is possible and while someone
138 // set mbUpdatePending to true in the middle of it.
141 UpdateConfiguration();
143 if (mbUpdatePending
&& IsUpdatePossible())
150 mbUpdatePending
= true;
151 #if defined VERBOSE && VERBOSE>=1
152 OSL_TRACE("scheduling update for later\n");
160 Reference
<XConfiguration
> ConfigurationUpdater::GetCurrentConfiguration (void) const
162 return mxCurrentConfiguration
;
168 Reference
<XConfiguration
> ConfigurationUpdater::GetRequestedConfiguration (void) const
170 return mxRequestedConfiguration
;
176 bool ConfigurationUpdater::IsUpdatePossible (void)
178 return ! mbUpdateBeingProcessed
179 && mxControllerManager
.is()
181 && mxRequestedConfiguration
.is()
182 && mxCurrentConfiguration
.is();
188 void ConfigurationUpdater::UpdateConfiguration (void)
190 #if defined VERBOSE && VERBOSE>=1
191 OSL_TRACE("UpdateConfiguration update\n");
193 SetUpdateBeingProcessed(true);
194 comphelper::ScopeGuard
aScopeGuard (
195 ::boost::bind(&ConfigurationUpdater::SetUpdateBeingProcessed
, this, false));
199 mbUpdatePending
= false;
201 CleanRequestedConfiguration();
202 ConfigurationClassifier
aClassifier(mxRequestedConfiguration
, mxCurrentConfiguration
);
203 if (aClassifier
.Partition())
205 #if defined VERBOSE && VERBOSE>=2
206 OSL_TRACE("ConfigurationUpdater::UpdateConfiguration(\n");
207 ConfigurationTracer::TraceConfiguration(
208 mxRequestedConfiguration
, "requested configuration");
209 ConfigurationTracer::TraceConfiguration(
210 mxCurrentConfiguration
, "current configuration");
212 // Notify the begining of the update.
213 ConfigurationChangeEvent aEvent
;
214 aEvent
.Type
= FrameworkHelper::msConfigurationUpdateStartEvent
;
215 aEvent
.Configuration
= mxRequestedConfiguration
;
216 mpBroadcaster
->NotifyListeners(aEvent
);
218 // Do the actual update. All exceptions are caught and ignored,
219 // so that the the end of the update is notified always.
222 if (mnLockCount
== 0)
223 UpdateCore(aClassifier
);
225 catch(RuntimeException
)
229 // Notify the end of the update.
230 aEvent
.Type
= FrameworkHelper::msConfigurationUpdateEndEvent
;
231 mpBroadcaster
->NotifyListeners(aEvent
);
233 CheckUpdateSuccess();
237 #if defined VERBOSE && VERBOSE>0
238 OSL_TRACE("nothing to do\n");
239 #if defined VERBOSE && VERBOSE>=2
240 ConfigurationTracer::TraceConfiguration(
241 mxRequestedConfiguration
, "requested configuration");
242 ConfigurationTracer::TraceConfiguration(
243 mxCurrentConfiguration
, "current configuration");
248 catch (RuntimeException e
)
250 OSL_TRACE("caught exception while updating the current configuration");
251 DBG_ASSERT(false, "caught exception while updating the current configuration");
254 #if defined VERBOSE && VERBOSE>0
255 OSL_TRACE("ConfigurationUpdater::UpdateConfiguration)");
256 OSL_TRACE("UpdateConfiguration end");
263 void ConfigurationUpdater::CleanRequestedConfiguration (void)
265 if (mxControllerManager
.is())
267 // Request the deactivation of pure anchors that have no child.
268 vector
<Reference
<XResourceId
> > aResourcesToDeactivate
;
269 CheckPureAnchors(mxRequestedConfiguration
, aResourcesToDeactivate
);
270 if (aResourcesToDeactivate
.size() > 0)
272 Reference
<XConfigurationController
> xCC (
273 mxControllerManager
->getConfigurationController());
274 vector
<Reference
<XResourceId
> >::iterator iId
;
275 for (iId
=aResourcesToDeactivate
.begin(); iId
!=aResourcesToDeactivate
.end(); ++iId
)
277 xCC
->requestResourceDeactivation(*iId
);
285 void ConfigurationUpdater::CheckUpdateSuccess (void)
287 // When the two configurations differ then start the timer to call
288 // another update later.
289 if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration
, mxRequestedConfiguration
))
291 if (mnFailedUpdateCount
<= snShortTimeoutCountThreshold
)
292 maUpdateTimer
.SetTimeout(snShortTimeout
);
293 else if (mnFailedUpdateCount
< snNormalTimeoutCountThreshold
)
294 maUpdateTimer
.SetTimeout(snNormalTimeout
);
296 maUpdateTimer
.SetTimeout(snLongTimeout
);
297 ++mnFailedUpdateCount
;
298 maUpdateTimer
.Start();
302 // Update was successfull. Reset the failed update count.
303 mnFailedUpdateCount
= 0;
310 void ConfigurationUpdater::UpdateCore (const ConfigurationClassifier
& rClassifier
)
314 #if defined VERBOSE && VERBOSE>=2
315 rClassifier
.TraceResourceIdVector(
316 "requested but not current resources:\n", rClassifier
.GetC1minusC2());
317 rClassifier
.TraceResourceIdVector(
318 "current but not requested resources:\n", rClassifier
.GetC2minusC1());
319 rClassifier
.TraceResourceIdVector(
320 "requested and current resources:\n", rClassifier
.GetC1andC2());
323 // Updating of the sub controllers is done in two steps. In the
324 // first the sub controllers typically shut down resources that are
325 // not requested anymore. In the second the sub controllers
326 // typically set up resources that have been newly requested.
327 mpResourceManager
->DeactivateResources(rClassifier
.GetC2minusC1(), mxCurrentConfiguration
);
328 mpResourceManager
->ActivateResources(rClassifier
.GetC1minusC2(), mxCurrentConfiguration
);
330 #if defined VERBOSE && VERBOSE>=2
331 OSL_TRACE("ConfigurationController::UpdateConfiguration)\n");
332 ConfigurationTracer::TraceConfiguration(
333 mxRequestedConfiguration
, "requested configuration\n");
334 ConfigurationTracer::TraceConfiguration(
335 mxCurrentConfiguration
, "current configuration\n");
338 // Deactivate pure anchors that have no child.
339 vector
<Reference
<XResourceId
> > aResourcesToDeactivate
;
340 CheckPureAnchors(mxCurrentConfiguration
, aResourcesToDeactivate
);
341 if (aResourcesToDeactivate
.size() > 0)
342 mpResourceManager
->DeactivateResources(aResourcesToDeactivate
, mxCurrentConfiguration
);
344 catch(RuntimeException
)
353 void ConfigurationUpdater::CheckPureAnchors (
354 const Reference
<XConfiguration
>& rxConfiguration
,
355 vector
<Reference
<XResourceId
> >& rResourcesToDeactivate
)
357 if ( ! rxConfiguration
.is())
360 // Get a list of all resources in the configuration.
361 Sequence
<Reference
<XResourceId
> > aResources(
362 rxConfiguration
->getResources(
363 NULL
, OUString(), AnchorBindingMode_INDIRECT
));
364 sal_Int32
nCount (aResources
.getLength());
366 // Prepare the list of pure anchors that have to be deactivated.
367 rResourcesToDeactivate
.clear();
369 // Iterate over the list in reverse order because when there is a chain
370 // of pure anchors with only the last one having no child then the whole
371 // list has to be deactivated.
372 sal_Int32
nIndex (nCount
-1);
375 const Reference
<XResourceId
> xResourceId (aResources
[nIndex
]);
376 const Reference
<XResource
> xResource (
377 mpResourceManager
->GetResource(xResourceId
).mxResource
);
378 bool bDeactiveCurrentResource (false);
380 // Skip all resources that are no pure anchors.
381 if (xResource
.is() && xResource
->isAnchorOnly())
383 // When xResource is not an anchor of the the next resource in
384 // the list then it is the anchor of no resource at all.
385 if (nIndex
== nCount
-1)
387 // No following anchors, deactivate this one, then remove it
389 bDeactiveCurrentResource
= true;
393 const Reference
<XResourceId
> xPrevResourceId (aResources
[nIndex
+1]);
394 if ( ! xPrevResourceId
.is()
395 || ! xPrevResourceId
->isBoundTo(xResourceId
, AnchorBindingMode_DIRECT
))
397 // The previous resource (id) does not exist or is not bound to
398 // the current anchor.
399 bDeactiveCurrentResource
= true;
404 if (bDeactiveCurrentResource
)
406 #if defined VERBOSE && VERBOSE>=2
407 OSL_TRACE("deactiving pure anchor %s because it has no children\n",
409 FrameworkHelper::ResourceIdToString(xResourceId
),
410 RTL_TEXTENCODING_UTF8
).getStr());
412 // Erase element from current configuration.
413 for (sal_Int32 nI
=nIndex
; nI
<nCount
-2; ++nI
)
414 aResources
[nI
] = aResources
[nI
+1];
417 rResourcesToDeactivate
.push_back(xResourceId
);
426 void ConfigurationUpdater::LockUpdates (void)
434 void ConfigurationUpdater::UnlockUpdates (void)
437 if (mnLockCount
== 0 && mbUpdatePending
)
439 RequestUpdate(mxRequestedConfiguration
);
446 ::boost::shared_ptr
<ConfigurationUpdaterLock
> ConfigurationUpdater::GetLock (void)
448 return ::boost::shared_ptr
<ConfigurationUpdaterLock
>(new ConfigurationUpdaterLock(*this));
454 void ConfigurationUpdater::SetUpdateBeingProcessed (bool bValue
)
456 mbUpdateBeingProcessed
= bValue
;
462 IMPL_LINK(ConfigurationUpdater
, TimeoutHandler
, Timer
*, EMPTYARG
)
464 OSL_TRACE("configuration update timer\n");
465 if ( ! mbUpdateBeingProcessed
466 && mxCurrentConfiguration
.is()
467 && mxRequestedConfiguration
.is())
469 if ( ! AreConfigurationsEquivalent(mxCurrentConfiguration
, mxRequestedConfiguration
))
471 OSL_TRACE("configurations differ, requesting update\n");
472 RequestUpdate(mxRequestedConfiguration
);
479 } } // end of namespace sd::framework