1 /*
2 * Copyright (c) 2011-2014, Intel Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation and/or
13 * other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors
16 * may be used to endorse or promote products derived from this software without
17 * specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30 #include "ConfigurableDomain.h"
31 #include "DomainConfiguration.h"
32 #include "ConfigurableElement.h"
33 #include "ConfigurationAccessContext.h"
34 #include "XmlDomainSerializingContext.h"
35 #include "XmlDomainImportContext.h"
36 #include "XmlDomainExportContext.h"
37 #include <assert.h>
38
39 #define base CBinarySerializableElement
40
41 using std::string;
42
CConfigurableDomain()43 CConfigurableDomain::CConfigurableDomain() :
44 _bSequenceAware(false), _pLastAppliedConfiguration(NULL)
45 {
46 }
47
CConfigurableDomain(const string & strName)48 CConfigurableDomain::CConfigurableDomain(const string& strName) : base(strName), _bSequenceAware(false), _pLastAppliedConfiguration(NULL)
49 {
50 }
51
~CConfigurableDomain()52 CConfigurableDomain::~CConfigurableDomain()
53 {
54 // Remove all configurable elements
55 ConfigurableElementListIterator it;
56
57 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
58
59 CConfigurableElement* pConfigurableElement = *it;
60
61 // Remove from configurable element
62 pConfigurableElement->removeAttachedConfigurableDomain(this);
63 }
64
65 // Remove all associated syncer sets
66 ConfigurableElementToSyncerSetMapIterator mapIt;
67
68 for (mapIt = _configurableElementToSyncerSetMap.begin(); mapIt != _configurableElementToSyncerSetMap.end(); ++mapIt) {
69
70 delete mapIt->second;
71 }
72 }
73
getKind() const74 string CConfigurableDomain::getKind() const
75 {
76 return "ConfigurableDomain";
77 }
78
childrenAreDynamic() const79 bool CConfigurableDomain::childrenAreDynamic() const
80 {
81 return true;
82 }
83
84 // Content dumping
logValue(string & strValue,CErrorContext & errorContext) const85 void CConfigurableDomain::logValue(string& strValue, CErrorContext& errorContext) const
86 {
87 (void)errorContext;
88
89 strValue = "{";
90
91 // Sequence awareness
92 strValue += "Sequence aware: ";
93 strValue += _bSequenceAware ? "yes" : "no";
94
95 // Last applied configuration
96 strValue += ", Last applied configuration: ";
97 strValue += _pLastAppliedConfiguration ? _pLastAppliedConfiguration->getName() : "<none>";
98
99 strValue += "}";
100 }
101
102 // Sequence awareness
setSequenceAwareness(bool bSequenceAware)103 void CConfigurableDomain::setSequenceAwareness(bool bSequenceAware)
104 {
105 if (_bSequenceAware != bSequenceAware) {
106
107 log_info("Making domain \"%s\" sequence %s", getName().c_str(), bSequenceAware ? "aware" : "unaware");
108
109 _bSequenceAware = bSequenceAware;
110 }
111 }
112
getSequenceAwareness() const113 bool CConfigurableDomain::getSequenceAwareness() const
114 {
115 return _bSequenceAware;
116 }
117
118 // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const119 void CConfigurableDomain::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
120 {
121 base::toXml(xmlElement, serializingContext);
122
123 // Sequence awareness
124 xmlElement.setAttributeBoolean("SequenceAware", _bSequenceAware);
125 }
126
childrenToXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const127 void CConfigurableDomain::childrenToXml(CXmlElement& xmlElement,
128 CXmlSerializingContext& serializingContext) const
129 {
130 // Configurations
131 composeDomainConfigurations(xmlElement, serializingContext);
132
133 // Configurable Elements
134 composeConfigurableElements(xmlElement);
135
136 // Settings
137 composeSettings(xmlElement, serializingContext);
138 }
139
140 // XML composing
composeDomainConfigurations(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const141 void CConfigurableDomain::composeDomainConfigurations(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
142 {
143 // Create Configurations element
144 CXmlElement xmlConfigurationsElement;
145
146 xmlElement.createChild(xmlConfigurationsElement, "Configurations");
147
148 // Delegate to base
149 base::childrenToXml(xmlConfigurationsElement, serializingContext);
150 }
151
composeConfigurableElements(CXmlElement & xmlElement) const152 void CConfigurableDomain::composeConfigurableElements(CXmlElement& xmlElement) const
153 {
154 // Create ConfigurableElements element
155 CXmlElement xmlConfigurableElementsElement;
156
157 xmlElement.createChild(xmlConfigurableElementsElement, "ConfigurableElements");
158
159 // Serialize out all configurable elements settings
160 ConfigurableElementListIterator it;
161
162 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
163
164 const CConfigurableElement* pConfigurableElement = *it;
165
166 // Create corresponding XML child element
167 CXmlElement xmlChildConfigurableElement;
168
169 xmlConfigurableElementsElement.createChild(xmlChildConfigurableElement, "ConfigurableElement");
170
171 // Set Path attribute
172 xmlChildConfigurableElement.setAttributeString("Path", pConfigurableElement->getPath());
173 }
174 }
175
composeSettings(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const176 void CConfigurableDomain::composeSettings(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
177 {
178 // Context
179 const CXmlDomainExportContext& xmlDomainExportContext =
180 static_cast<const CXmlDomainExportContext&>(serializingContext);
181
182 if (!xmlDomainExportContext.withSettings()) {
183
184 return;
185 }
186
187 // Create Settings element
188 CXmlElement xmlSettingsElement;
189
190 xmlElement.createChild(xmlSettingsElement, "Settings");
191
192 // Serialize out all configurations settings
193 size_t uiNbConfigurations = getNbChildren();
194 size_t uiChildConfiguration;
195
196 for (uiChildConfiguration = 0; uiChildConfiguration < uiNbConfigurations; uiChildConfiguration++) {
197
198 const CDomainConfiguration* pDomainConfiguration = static_cast<const CDomainConfiguration*>(getChild(uiChildConfiguration));
199
200 // Create child xml element for that configuration
201 CXmlElement xmlConfigurationSettingsElement;
202
203 xmlSettingsElement.createChild(xmlConfigurationSettingsElement, pDomainConfiguration->getKind());
204
205 // Set its name attribute
206 xmlConfigurationSettingsElement.setNameAttribute(pDomainConfiguration->getName());
207
208 // Serialize out configuration settings
209 pDomainConfiguration->composeSettings(xmlConfigurationSettingsElement, serializingContext);
210 }
211 }
212
213 // From IXmlSink
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)214 bool CConfigurableDomain::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
215 {
216 // Context
217 CXmlDomainImportContext& xmlDomainImportContext =
218 static_cast<CXmlDomainImportContext&>(serializingContext);
219
220 // Sequence awareness (optional)
221 _bSequenceAware = xmlElement.hasAttribute("SequenceAware") && xmlElement.getAttributeBoolean("SequenceAware");
222
223 setName(xmlElement.getAttributeString("Name"));
224
225 // Local parsing. Do not dig
226 if (!parseDomainConfigurations(xmlElement, xmlDomainImportContext) ||
227 !parseConfigurableElements(xmlElement, xmlDomainImportContext) ||
228 !parseSettings(xmlElement, xmlDomainImportContext)) {
229
230 return false;
231 }
232
233 // All provided configurations are parsed
234 // Attempt validation on areas of non provided configurations for all configurable elements if required
235 if (xmlDomainImportContext.autoValidationRequired()) {
236
237 autoValidateAll();
238 }
239
240 return true;
241 }
242
243 // XML parsing
parseDomainConfigurations(const CXmlElement & xmlElement,CXmlDomainImportContext & serializingContext)244 bool CConfigurableDomain::parseDomainConfigurations(const CXmlElement& xmlElement,
245 CXmlDomainImportContext& serializingContext)
246 {
247 // We're supposedly clean
248 assert(_configurableElementList.empty());
249
250 // Get Configurations element
251 CXmlElement xmlConfigurationsElement;
252
253 xmlElement.getChildElement("Configurations", xmlConfigurationsElement);
254
255 // Parse it and create domain configuration objects
256 return base::fromXml(xmlConfigurationsElement, serializingContext);
257 }
258
259 // Parse configurable elements
parseConfigurableElements(const CXmlElement & xmlElement,CXmlDomainImportContext & serializingContext)260 bool CConfigurableDomain::parseConfigurableElements(const CXmlElement& xmlElement,
261 CXmlDomainImportContext& serializingContext)
262 {
263 CSystemClass& systemClass = serializingContext.getSystemClass();
264
265 // Get ConfigurableElements element
266 CXmlElement xmlConfigurableElementsElement;
267 xmlElement.getChildElement("ConfigurableElements", xmlConfigurableElementsElement);
268
269 // Parse it and associate found configurable elements to it
270 CXmlElement::CChildIterator it(xmlConfigurableElementsElement);
271
272 CXmlElement xmlConfigurableElementElement;
273
274 while (it.next(xmlConfigurableElementElement)) {
275
276 // Locate configurable element
277 string strConfigurableElementPath = xmlConfigurableElementElement.getAttributeString("Path");
278
279 CPathNavigator pathNavigator(strConfigurableElementPath);
280 string strError;
281
282 // Is there an element and does it match system class name?
283 if (!pathNavigator.navigateThrough(systemClass.getName(), strError)) {
284
285 serializingContext.setError("Could not find configurable element of path " + strConfigurableElementPath + " from ConfigurableDomain description " + getName() + " (" + strError + ")");
286
287 return false;
288 }
289 // Browse system class for configurable element
290 CConfigurableElement* pConfigurableElement =
291 static_cast<CConfigurableElement*>(systemClass.findDescendant(pathNavigator));
292
293 if (!pConfigurableElement) {
294
295 serializingContext.setError("Could not find configurable element of path " + strConfigurableElementPath + " from ConfigurableDomain description " + getName());
296
297 return false;
298 }
299 // Add found element to domain
300 if (!addConfigurableElement(pConfigurableElement, NULL, strError)) {
301
302 serializingContext.setError(strError);
303
304 return false;
305 }
306 }
307
308 return true;
309 }
310
311 // Parse settings
parseSettings(const CXmlElement & xmlElement,CXmlDomainImportContext & serializingContext)312 bool CConfigurableDomain::parseSettings(const CXmlElement& xmlElement,
313 CXmlDomainImportContext& serializingContext)
314 {
315 // Check we actually need to parse configuration settings
316 if (!serializingContext.withSettings()) {
317
318 // No parsing required
319 return true;
320 }
321
322 // Get Settings element
323 CXmlElement xmlSettingsElement;
324 if (!xmlElement.getChildElement("Settings", xmlSettingsElement)) {
325
326 // No settings, bail out successfully
327 return true;
328 }
329
330 // Parse configuration settings
331 CXmlElement::CChildIterator it(xmlSettingsElement);
332
333 CXmlElement xmlConfigurationSettingsElement;
334
335 while (it.next(xmlConfigurationSettingsElement)) {
336 // Get domain configuration
337 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(findChild(xmlConfigurationSettingsElement.getNameAttribute()));
338
339 if (!pDomainConfiguration) {
340
341 serializingContext.setError("Could not find domain configuration referred to by"
342 " configurable domain \"" + getName() + "\".");
343
344 return false;
345 }
346 // Have domain configuration parse settings for all configurable elements
347 if (!pDomainConfiguration->parseSettings(xmlConfigurationSettingsElement,
348 serializingContext)) {
349
350 return false;
351 }
352 }
353
354 return true;
355 }
356 // Configurable elements association
addConfigurableElement(CConfigurableElement * pConfigurableElement,const CParameterBlackboard * pMainBlackboard,string & strError)357 bool CConfigurableDomain::addConfigurableElement(CConfigurableElement* pConfigurableElement, const CParameterBlackboard* pMainBlackboard, string& strError)
358 {
359 // Already associated?
360 if (containsConfigurableElement(pConfigurableElement)) {
361
362 strError = "Configurable element " + pConfigurableElement->getPath() + " already associated to configuration domain " + getName();
363
364 return false;
365 }
366
367 // Already owned?
368 if (pConfigurableElement->belongsTo(this)) {
369
370 strError = "Configurable element " + pConfigurableElement->getPath() + " already owned by configuration domain " + getName();
371
372 return false;
373 }
374
375 // Do add
376 doAddConfigurableElement(pConfigurableElement, pMainBlackboard);
377
378 return true;
379 }
380
removeConfigurableElement(CConfigurableElement * pConfigurableElement,string & strError)381 bool CConfigurableDomain::removeConfigurableElement(CConfigurableElement* pConfigurableElement, string& strError)
382 {
383 // Not associated?
384 if (!containsConfigurableElement(pConfigurableElement)) {
385
386 strError = "Configurable element " + pConfigurableElement->getPath() + " not associated to configuration domain " + getName();
387
388 return false;
389 }
390 log_info("Removing configurable element \"%s\" from domain \"%s\"", pConfigurableElement->getPath().c_str(), getName().c_str());
391
392 // Do remove
393 doRemoveConfigurableElement(pConfigurableElement, true);
394
395 return true;
396 }
397
398 /**
399 * Blackboard Configuration and Base Offset retrieval.
400 *
401 * This method fetches the Blackboard associated to the ConfigurableElement
402 * given in parameter, for a specific Configuration. The ConfigurableElement
403 * must belong to the Domain. If a Blackboard is found, the base offset of
404 * the ConfigurableElement is returned as well. This base offset corresponds to
405 * the offset of the ancestor of the ConfigurableElement associated to the Configuration.
406 *
407 * @param[in] strConfiguration Name of the Configuration.
408 * @param[in] pCandidateDescendantConfigurableElement Pointer to a CConfigurableElement that
409 * belongs to the Domain.
410 * @param[out] uiBaseOffset The base offset of the CConfigurableElement.
411 * @param[out] bIsLastApplied Boolean indicating that the Configuration is
412 * the last one applied of the Domain.
413 * @param[out] strError Error message
414 *
415 * return Pointer to the Blackboard of the Configuration.
416 */
findConfigurationBlackboard(const string & strConfiguration,const CConfigurableElement * pCandidateDescendantConfigurableElement,uint32_t & uiBaseOffset,bool & bIsLastApplied,string & strError) const417 CParameterBlackboard* CConfigurableDomain::findConfigurationBlackboard(const string& strConfiguration,
418 const CConfigurableElement* pCandidateDescendantConfigurableElement,
419 uint32_t& uiBaseOffset,
420 bool& bIsLastApplied,
421 string& strError) const
422 {
423 // Find Configuration
424 const CDomainConfiguration* pDomainConfiguration = static_cast<const CDomainConfiguration*>(findChild(strConfiguration));
425
426 if (!pDomainConfiguration) {
427
428 strError = "Domain configuration " + strConfiguration + " not found";
429
430 return NULL;
431 }
432
433 // Parse all configurable elements
434 ConfigurableElementListIterator it;
435
436 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
437
438 const CConfigurableElement* pAssociatedConfigurableElement = *it;
439
440 // Check if the the associated element is the configurable element or one of its ancestors
441 if ((pCandidateDescendantConfigurableElement == pAssociatedConfigurableElement) ||
442 (pCandidateDescendantConfigurableElement->isDescendantOf(pAssociatedConfigurableElement))) {
443
444 uiBaseOffset = pAssociatedConfigurableElement->getOffset();
445 bIsLastApplied = (pDomainConfiguration == _pLastAppliedConfiguration);
446
447 return pDomainConfiguration->getBlackboard(pAssociatedConfigurableElement);
448 }
449 }
450
451 strError = "Element not associated to the Domain";
452
453 return NULL;
454 }
455
456 // Domain splitting
split(CConfigurableElement * pConfigurableElement,string & strError)457 bool CConfigurableDomain::split(CConfigurableElement* pConfigurableElement, string& strError)
458 {
459 // Not associated?
460 if (!containsConfigurableElement(pConfigurableElement)) {
461
462 strError = "Configurable element " + pConfigurableElement->getPath() + " not associated to configuration domain " + getName();
463
464 return false;
465 }
466 log_info("Splitting configurable element \"%s\" domain \"%s\"", pConfigurableElement->getPath().c_str(), getName().c_str());
467
468 // Create sub domain areas for all configurable element's children
469 size_t uiNbConfigurableElementChildren = pConfigurableElement->getNbChildren();
470
471 if (!uiNbConfigurableElementChildren) {
472
473 strError = "Configurable element " + pConfigurableElement->getPath() + " has no children to split configurable domain to";
474
475 return false;
476 }
477
478 size_t uiChild;
479
480 for (uiChild = 0; uiChild < uiNbConfigurableElementChildren; uiChild++) {
481
482 CConfigurableElement* pChildConfigurableElement = static_cast<CConfigurableElement*>(pConfigurableElement->getChild(uiChild));
483
484 doAddConfigurableElement(pChildConfigurableElement);
485 }
486
487 // Delegate to configurations
488 size_t uiNbConfigurations = getNbChildren();
489
490 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
491
492 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(getChild(uiChild));
493
494 pDomainConfiguration->split(pConfigurableElement);
495 }
496
497 // Remove given configurable element from this domain
498 // Note: we shouldn't need to recompute the sync set in that case, as the splitted element should include the syncers of its children elements
499 doRemoveConfigurableElement(pConfigurableElement, false);
500
501 return true;
502 }
503
504 // Check if there is a pending configuration for this domain: i.e. an applicable configuration different from the last applied configuration
getPendingConfiguration() const505 const CDomainConfiguration* CConfigurableDomain::getPendingConfiguration() const
506 {
507 const CDomainConfiguration* pApplicableDomainConfiguration = findApplicableDomainConfiguration();
508
509 if (pApplicableDomainConfiguration) {
510
511 // Check not the last one before applying
512 if (!_pLastAppliedConfiguration || (_pLastAppliedConfiguration != pApplicableDomainConfiguration)) {
513
514 return pApplicableDomainConfiguration;
515 }
516 }
517
518 return NULL;
519 }
520
521 // Configuration application if required
apply(CParameterBlackboard * pParameterBlackboard,CSyncerSet * pSyncerSet,bool bForce) const522 void CConfigurableDomain::apply(CParameterBlackboard* pParameterBlackboard, CSyncerSet* pSyncerSet, bool bForce) const
523 {
524 // Apply configuration only if the blackboard will
525 // be synchronized either now or by syncerSet.
526 if(!pSyncerSet ^ _bSequenceAware) {
527 // The configuration can not be syncronised
528 return;
529 }
530
531 if (bForce) {
532 // Force a configuration restore by forgetting about last applied configuration
533 _pLastAppliedConfiguration = NULL;
534 }
535 const CDomainConfiguration* pApplicableDomainConfiguration = findApplicableDomainConfiguration();
536
537 if (pApplicableDomainConfiguration) {
538
539 // Check not the last one before applying
540 if (!_pLastAppliedConfiguration || _pLastAppliedConfiguration != pApplicableDomainConfiguration) {
541
542 log_info("Applying configuration \"%s\" from domain \"%s\"",
543 pApplicableDomainConfiguration->getName().c_str(),
544 getName().c_str());
545
546 // Check if we need to synchronize during restore
547 bool bSync = !pSyncerSet && _bSequenceAware;
548
549 // Do the restore
550 pApplicableDomainConfiguration->restore(pParameterBlackboard, bSync, NULL);
551
552 // Record last applied configuration
553 _pLastAppliedConfiguration = pApplicableDomainConfiguration;
554
555 // Check we need to provide syncer set to caller
556 if (pSyncerSet && !_bSequenceAware) {
557
558 // Since we applied changes, add our own sync set to the given one
559 *pSyncerSet += _syncerSet;
560 }
561 }
562 }
563 }
564
565 // Return applicable configuration validity for given configurable element
isApplicableConfigurationValid(const CConfigurableElement * pConfigurableElement) const566 bool CConfigurableDomain::isApplicableConfigurationValid(const CConfigurableElement* pConfigurableElement) const
567 {
568 const CDomainConfiguration* pApplicableDomainConfiguration = findApplicableDomainConfiguration();
569
570 return pApplicableDomainConfiguration && pApplicableDomainConfiguration->isValid(pConfigurableElement);
571 }
572
573 // In case configurable element was removed
computeSyncSet()574 void CConfigurableDomain::computeSyncSet()
575 {
576 // Clean sync set first
577 _syncerSet.clear();
578
579 // Add syncer sets for all associated configurable elements
580 ConfigurableElementToSyncerSetMapIterator mapIt;
581
582 for (mapIt = _configurableElementToSyncerSetMap.begin(); mapIt != _configurableElementToSyncerSetMap.end(); ++mapIt) {
583
584 const CSyncerSet* pSyncerSet = mapIt->second;
585
586 _syncerSet += *pSyncerSet;
587 }
588 }
589
590 // Configuration Management
createConfiguration(const string & strName,const CParameterBlackboard * pMainBlackboard,string & strError)591 bool CConfigurableDomain::createConfiguration(const string& strName, const CParameterBlackboard* pMainBlackboard, string& strError)
592 {
593 // Already exists?
594 if (findChild(strName)) {
595
596 strError = "Already existing configuration";
597
598 return false;
599 }
600 log_info("Creating domain configuration \"%s\" into domain \"%s\"", strName.c_str(), getName().c_str());
601
602 // Creation
603 CDomainConfiguration* pDomainConfiguration = new CDomainConfiguration(strName);
604
605 // Configurable elements association
606 ConfigurableElementListIterator it;
607
608 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
609
610 const CConfigurableElement* pConfigurableElement = *it;;
611
612 // Retrieve associated syncer set
613 CSyncerSet* pSyncerSet = getSyncerSet(pConfigurableElement);
614
615 // Associate to configuration
616 pDomainConfiguration->addConfigurableElement(pConfigurableElement, pSyncerSet);
617 }
618
619 // Hierarchy
620 addChild(pDomainConfiguration);
621
622 // Ensure validity of fresh new domain configuration
623 // Attempt auto validation, so that the user gets his/her own settings by defaults
624 if (!autoValidateConfiguration(pDomainConfiguration)) {
625
626 // No valid configuration found to copy in from, validate againt main blackboard (will concerned remaining invalid parts)
627 pDomainConfiguration->validate(pMainBlackboard);
628 }
629
630 return true;
631 }
632
deleteConfiguration(const string & strName,string & strError)633 bool CConfigurableDomain::deleteConfiguration(const string& strName, string& strError)
634 {
635 CDomainConfiguration* pDomainConfiguration = findConfiguration(strName, strError);
636
637 if (!pDomainConfiguration) {
638
639 return false;
640 }
641
642 log_info("Deleting configuration \"%s\" from domain \"%s\"", strName.c_str(), getName().c_str());
643
644 // Was the last applied?
645 if (pDomainConfiguration == _pLastAppliedConfiguration) {
646
647 // Forget about it
648 _pLastAppliedConfiguration = NULL;
649 }
650
651 // Hierarchy
652 removeChild(pDomainConfiguration);
653
654 // Destroy
655 delete pDomainConfiguration;
656
657 return true;
658 }
659
listAssociatedToElements(string & strResult) const660 void CConfigurableDomain::listAssociatedToElements(string& strResult) const
661 {
662 strResult = "\n";
663
664 ConfigurableElementListIterator it;
665
666 // Browse all configurable elements
667 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
668
669 const CConfigurableElement* pConfigurableElement = *it;
670
671 strResult += pConfigurableElement->getPath() + "\n";
672 }
673 }
674
renameConfiguration(const string & strName,const string & strNewName,string & strError)675 bool CConfigurableDomain::renameConfiguration(const string& strName, const string& strNewName, string& strError)
676 {
677 CDomainConfiguration* pDomainConfiguration = findConfiguration(strName, strError);
678
679 if (!pDomainConfiguration) {
680
681 return false;
682 }
683 log_info("Renaming domain \"%s\"'s configuration \"%s\" to \"%s\"", getName().c_str(), strName.c_str(), strNewName.c_str());
684
685 // Rename
686 return pDomainConfiguration->rename(strNewName, strError);
687 }
688
restoreConfiguration(const string & strName,CParameterBlackboard * pMainBlackboard,bool bAutoSync,std::list<string> & lstrError) const689 bool CConfigurableDomain::restoreConfiguration(const string& strName, CParameterBlackboard* pMainBlackboard, bool bAutoSync, std::list<string>& lstrError) const
690 {
691 string strError;
692
693 const CDomainConfiguration* pDomainConfiguration = findConfiguration(strName, strError);
694
695 if (!pDomainConfiguration) {
696
697 lstrError.push_back(strError);
698 return false;
699 }
700 log_info("Restoring domain \"%s\"'s configuration \"%s\" to parameter blackboard", getName().c_str(), pDomainConfiguration->getName().c_str());
701
702 // Delegate
703 bool bSuccess = pDomainConfiguration->restore(pMainBlackboard, bAutoSync && _bSequenceAware, &lstrError);
704
705 // Record last applied configuration
706 _pLastAppliedConfiguration = pDomainConfiguration;
707
708 // Synchronize
709 if (bAutoSync && !_bSequenceAware) {
710
711 bSuccess &= _syncerSet.sync(*pMainBlackboard, false, &lstrError);
712 }
713 return bSuccess;
714 }
715
saveConfiguration(const string & strName,const CParameterBlackboard * pMainBlackboard,string & strError)716 bool CConfigurableDomain::saveConfiguration(const string& strName, const CParameterBlackboard* pMainBlackboard, string& strError)
717 {
718 // Find Domain configuration
719 CDomainConfiguration* pDomainConfiguration = findConfiguration(strName, strError);
720
721 if (!pDomainConfiguration) {
722
723 return false;
724 }
725 log_info("Saving domain \"%s\"'s configuration \"%s\" from parameter blackboard", getName().c_str(), pDomainConfiguration->getName().c_str());
726
727 // Delegate
728 pDomainConfiguration->save(pMainBlackboard);
729
730 return true;
731 }
732
setElementSequence(const string & strConfiguration,const std::vector<string> & astrNewElementSequence,string & strError)733 bool CConfigurableDomain::setElementSequence(const string& strConfiguration, const std::vector<string>& astrNewElementSequence, string& strError)
734 {
735 // Find Domain configuration
736 CDomainConfiguration* pDomainConfiguration = findConfiguration(strConfiguration, strError);
737
738 if (!pDomainConfiguration) {
739
740 return false;
741 }
742
743 // Delegate to configuration
744 return pDomainConfiguration->setElementSequence(astrNewElementSequence, strError);
745 }
746
getElementSequence(const string & strConfiguration,string & strResult) const747 bool CConfigurableDomain::getElementSequence(const string& strConfiguration, string& strResult) const
748 {
749 // Find Domain configuration
750 const CDomainConfiguration* pDomainConfiguration = findConfiguration(strConfiguration, strResult);
751
752 if (!pDomainConfiguration) {
753
754 return false;
755 }
756
757 // Delegate to configuration
758 pDomainConfiguration->getElementSequence(strResult);
759
760 return true;
761 }
762
setApplicationRule(const string & strConfiguration,const string & strApplicationRule,const CSelectionCriteriaDefinition * pSelectionCriteriaDefinition,string & strError)763 bool CConfigurableDomain::setApplicationRule(const string& strConfiguration, const string& strApplicationRule, const CSelectionCriteriaDefinition* pSelectionCriteriaDefinition, string& strError)
764 {
765 // Find Domain configuration
766 CDomainConfiguration* pDomainConfiguration = findConfiguration(strConfiguration, strError);
767
768 if (!pDomainConfiguration) {
769
770 return false;
771 }
772
773 // Delegate to configuration
774 return pDomainConfiguration->setApplicationRule(strApplicationRule, pSelectionCriteriaDefinition, strError);
775 }
776
clearApplicationRule(const string & strConfiguration,string & strError)777 bool CConfigurableDomain::clearApplicationRule(const string& strConfiguration, string& strError)
778 {
779 // Find Domain configuration
780 CDomainConfiguration* pDomainConfiguration = findConfiguration(strConfiguration, strError);
781
782 if (!pDomainConfiguration) {
783
784 return false;
785 }
786
787 // Delegate to configuration
788 pDomainConfiguration->clearApplicationRule();
789
790 return true;
791 }
792
getApplicationRule(const string & strConfiguration,string & strResult) const793 bool CConfigurableDomain::getApplicationRule(const string& strConfiguration, string& strResult) const
794 {
795 // Find Domain configuration
796 const CDomainConfiguration* pDomainConfiguration = findConfiguration(strConfiguration, strResult);
797
798 if (!pDomainConfiguration) {
799
800 return false;
801 }
802
803 // Delegate to configuration
804 pDomainConfiguration->getApplicationRule(strResult);
805
806 return true;
807 }
808
809 // Last applied configuration
getLastAppliedConfigurationName() const810 string CConfigurableDomain::getLastAppliedConfigurationName() const
811 {
812 if (_pLastAppliedConfiguration) {
813
814 return _pLastAppliedConfiguration->getName();
815 }
816 return "<none>";
817 }
818
819 // Pending configuration
getPendingConfigurationName() const820 string CConfigurableDomain::getPendingConfigurationName() const
821 {
822 const CDomainConfiguration* pPendingConfiguration = getPendingConfiguration();
823
824 if (pPendingConfiguration) {
825
826 return pPendingConfiguration->getName();
827 }
828 return "<none>";
829 }
830
831 // Ensure validity on whole domain from main blackboard
validate(const CParameterBlackboard * pMainBlackboard)832 void CConfigurableDomain::validate(const CParameterBlackboard* pMainBlackboard)
833 {
834
835 // Propagate
836 size_t uiNbConfigurations = getNbChildren();
837 size_t uiChild;
838
839 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
840
841 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(getChild(uiChild));
842
843 pDomainConfiguration->validate(pMainBlackboard);
844 }
845 }
846
847 // Ensure validity on areas related to configurable element
validateAreas(const CConfigurableElement * pConfigurableElement,const CParameterBlackboard * pMainBlackboard)848 void CConfigurableDomain::validateAreas(const CConfigurableElement* pConfigurableElement, const CParameterBlackboard* pMainBlackboard)
849 {
850 log_info("Validating domain \"%s\" against main blackboard for configurable element \"%s\"", getName().c_str(), pConfigurableElement->getPath().c_str());
851
852 // Propagate
853 size_t uiNbConfigurations = getNbChildren();
854 size_t uiChild;
855
856 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
857
858 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(getChild(uiChild));
859
860 pDomainConfiguration->validate(pConfigurableElement, pMainBlackboard);
861 }
862 }
863
864 // Attempt validation for all configurable element's areas, relying on already existing valid configuration inside domain
autoValidateAll()865 void CConfigurableDomain::autoValidateAll()
866 {
867 // Validate
868 ConfigurableElementListIterator it;
869
870 // Browse all configurable elements for configuration validation
871 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
872
873 const CConfigurableElement* pConfigurableElement = *it;
874
875 // Auto validate element
876 autoValidateAreas(pConfigurableElement);
877 }
878 }
879
880 // Attempt validation for configurable element's areas, relying on already existing valid configuration inside domain
autoValidateAreas(const CConfigurableElement * pConfigurableElement)881 void CConfigurableDomain::autoValidateAreas(const CConfigurableElement* pConfigurableElement)
882 {
883 // Find first valid configuration for given configurable element
884 const CDomainConfiguration* pValidDomainConfiguration = findValidDomainConfiguration(pConfigurableElement);
885
886 // No valid configuration found, give up
887 if (!pValidDomainConfiguration) {
888
889 return;
890 }
891
892 // Validate all other configurations against found one, if any
893 size_t uiNbConfigurations = getNbChildren();
894 size_t uiChild;
895
896 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
897
898 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(getChild(uiChild));
899
900 if (pDomainConfiguration != pValidDomainConfiguration && !pDomainConfiguration->isValid(pConfigurableElement)) {
901 // Validate
902 pDomainConfiguration->validateAgainst(pValidDomainConfiguration, pConfigurableElement);
903 }
904 }
905 }
906
907 // Attempt configuration validation for all configurable elements' areas, relying on already existing valid configuration inside domain
autoValidateConfiguration(CDomainConfiguration * pDomainConfiguration)908 bool CConfigurableDomain::autoValidateConfiguration(CDomainConfiguration* pDomainConfiguration)
909 {
910 // Find another configuration than this one, that ought to be valid!
911 size_t uiNbConfigurations = getNbChildren();
912 size_t uiChild;
913
914 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
915
916 const CDomainConfiguration* pPotententialValidDomainConfiguration = static_cast<const CDomainConfiguration*>(getChild(uiChild));
917
918 if (pPotententialValidDomainConfiguration != pDomainConfiguration) {
919
920 // Validate against it
921 pDomainConfiguration->validateAgainst(pPotententialValidDomainConfiguration);
922
923 return true;
924 }
925 }
926 return false;
927 }
928
929 // Search for a valid configuration for given configurable element
findValidDomainConfiguration(const CConfigurableElement * pConfigurableElement) const930 const CDomainConfiguration* CConfigurableDomain::findValidDomainConfiguration(const CConfigurableElement* pConfigurableElement) const
931 {
932 size_t uiNbConfigurations = getNbChildren();
933 size_t uiChild;
934
935 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
936
937 const CDomainConfiguration* pDomainConfiguration = static_cast<const CDomainConfiguration*>(getChild(uiChild));
938
939 if (pDomainConfiguration->isValid(pConfigurableElement)) {
940
941 return pDomainConfiguration;
942 }
943 }
944 return NULL;
945 }
946
947 // Search for an applicable configuration
findApplicableDomainConfiguration() const948 const CDomainConfiguration* CConfigurableDomain::findApplicableDomainConfiguration() const
949 {
950 size_t uiNbConfigurations = getNbChildren();
951 size_t uiChild;
952
953 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
954
955 const CDomainConfiguration* pDomainConfiguration = static_cast<const CDomainConfiguration*>(getChild(uiChild));
956
957 if (pDomainConfiguration->isApplicable()) {
958
959 return pDomainConfiguration;
960 }
961 }
962 return NULL;
963 }
964
965 // Gather set of configurable elements
gatherConfigurableElements(std::set<const CConfigurableElement * > & configurableElementSet) const966 void CConfigurableDomain::gatherConfigurableElements(std::set<const CConfigurableElement*>& configurableElementSet) const
967 {
968 // Insert all configurable elements
969 configurableElementSet.insert(_configurableElementList.begin(), _configurableElementList.end());
970 }
971
972 // Check configurable element already attached
containsConfigurableElement(const CConfigurableElement * pConfigurableCandidateElement) const973 bool CConfigurableDomain::containsConfigurableElement(const CConfigurableElement* pConfigurableCandidateElement) const
974 {
975 ConfigurableElementListIterator it;
976
977 // Browse all configurable elements for comparison
978 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
979
980 if (pConfigurableCandidateElement == *it) {
981
982 return true;
983 }
984 }
985 return false;
986 }
987
988 // Merge any descended configurable element to this one with this one
mergeAlreadyAssociatedDescendantConfigurableElements(CConfigurableElement * pNewConfigurableElement)989 void CConfigurableDomain::mergeAlreadyAssociatedDescendantConfigurableElements(CConfigurableElement* pNewConfigurableElement)
990 {
991 std::list<CConfigurableElement*> mergedConfigurableElementList;
992
993 ConfigurableElementListIterator it;
994
995 // Browse all configurable elements (new one not yet in the list!)
996 for (it = _configurableElementList.begin(); it != _configurableElementList.end(); ++it) {
997
998 CConfigurableElement* pConfigurablePotentialDescendantElement = *it;
999
1000 if (pConfigurablePotentialDescendantElement->isDescendantOf(pNewConfigurableElement)) {
1001
1002 log_info("In domain \"%s\", merging descendant configurable element's configurations \"%s\" into its ascendant \"%s\" ones", getName().c_str(), pConfigurablePotentialDescendantElement->getName().c_str(), pNewConfigurableElement->getName().c_str());
1003
1004 // Merge configuration data
1005 mergeConfigurations(pNewConfigurableElement, pConfigurablePotentialDescendantElement);
1006
1007 // Keep track for removal
1008 mergedConfigurableElementList.push_back(pConfigurablePotentialDescendantElement);
1009 }
1010 }
1011
1012 // Remove all merged elements (new one not yet in the list!)
1013 for (it = mergedConfigurableElementList.begin(); it != mergedConfigurableElementList.end(); ++it) {
1014
1015 CConfigurableElement* pMergedConfigurableElement = *it;
1016
1017 // Remove merged from configurable element from internal tracking list
1018 // Note: we shouldn't need to recompute the sync set in that case, as the merged to element should include the syncers of merged from elements
1019 doRemoveConfigurableElement(pMergedConfigurableElement, false);
1020 }
1021 }
1022
mergeConfigurations(CConfigurableElement * pToConfigurableElement,CConfigurableElement * pFromConfigurableElement)1023 void CConfigurableDomain::mergeConfigurations(CConfigurableElement* pToConfigurableElement, CConfigurableElement* pFromConfigurableElement)
1024 {
1025 // Propagate to domain configurations
1026 size_t uiNbConfigurations = getNbChildren();
1027 size_t uiChild;
1028
1029 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
1030
1031 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(getChild(uiChild));
1032
1033 // Do the merge.
1034 pDomainConfiguration->merge(pToConfigurableElement, pFromConfigurableElement);
1035 }
1036 }
1037
1038 // Configurable elements association
doAddConfigurableElement(CConfigurableElement * pConfigurableElement,const CParameterBlackboard * pMainBlackboard)1039 void CConfigurableDomain::doAddConfigurableElement(CConfigurableElement* pConfigurableElement, const CParameterBlackboard *pMainBlackboard)
1040 {
1041 // Inform configurable element
1042 pConfigurableElement->addAttachedConfigurableDomain(this);
1043
1044 // Create associated syncer set
1045 CSyncerSet* pSyncerSet = new CSyncerSet;
1046
1047 // Add to sync set the configurable element one
1048 pConfigurableElement->fillSyncerSet(*pSyncerSet);
1049
1050 // Store it
1051 _configurableElementToSyncerSetMap[pConfigurableElement] = pSyncerSet;
1052
1053 // Add it to global one
1054 _syncerSet += *pSyncerSet;
1055
1056 // Inform configurations
1057 size_t uiNbConfigurations = getNbChildren();
1058 size_t uiChild;
1059
1060 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
1061
1062 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(getChild(uiChild));
1063
1064 pDomainConfiguration->addConfigurableElement(pConfigurableElement, pSyncerSet);
1065 }
1066
1067 // Ensure area validity for that configurable element (if main blackboard provided)
1068 if (pMainBlackboard) {
1069
1070 // Need to validate against main blackboard
1071 validateAreas(pConfigurableElement, pMainBlackboard);
1072 }
1073
1074 // Already associated descendend configurable elements need a merge of their configuration data
1075 mergeAlreadyAssociatedDescendantConfigurableElements(pConfigurableElement);
1076
1077 // Add to list
1078 _configurableElementList.push_back(pConfigurableElement);
1079 }
1080
doRemoveConfigurableElement(CConfigurableElement * pConfigurableElement,bool bRecomputeSyncSet)1081 void CConfigurableDomain::doRemoveConfigurableElement(CConfigurableElement* pConfigurableElement, bool bRecomputeSyncSet)
1082 {
1083 // Remove from list
1084 _configurableElementList.remove(pConfigurableElement);
1085
1086 // Remove associated syncer set
1087 CSyncerSet* pSyncerSet = getSyncerSet(pConfigurableElement);
1088
1089 _configurableElementToSyncerSetMap.erase(pConfigurableElement);
1090
1091 delete pSyncerSet;
1092
1093 // Inform configurable element
1094 pConfigurableElement->removeAttachedConfigurableDomain(this);
1095
1096 // Inform configurations
1097 size_t uiNbConfigurations = getNbChildren();
1098 size_t uiChild;
1099
1100 for (uiChild = 0; uiChild < uiNbConfigurations; uiChild++) {
1101
1102 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(getChild(uiChild));
1103
1104 pDomainConfiguration->removeConfigurableElement(pConfigurableElement);
1105 }
1106 // Recompute our sync set if needed
1107 if (bRecomputeSyncSet) {
1108
1109 computeSyncSet();
1110 }
1111 }
1112
1113 // Syncer set retrieval from configurable element
getSyncerSet(const CConfigurableElement * pConfigurableElement) const1114 CSyncerSet* CConfigurableDomain::getSyncerSet(const CConfigurableElement* pConfigurableElement) const
1115 {
1116 ConfigurableElementToSyncerSetMapIterator mapIt = _configurableElementToSyncerSetMap.find(pConfigurableElement);
1117
1118 assert(mapIt != _configurableElementToSyncerSetMap.end());
1119
1120 return mapIt->second;
1121 }
1122
1123 // Configuration retrieval
findConfiguration(const string & strConfiguration,string & strError)1124 CDomainConfiguration* CConfigurableDomain::findConfiguration(const string& strConfiguration, string& strError)
1125 {
1126 CDomainConfiguration* pDomainConfiguration = static_cast<CDomainConfiguration*>(findChild(strConfiguration));
1127
1128 if (!pDomainConfiguration) {
1129
1130 strError = "Domain configuration " + strConfiguration + " not found";
1131
1132 return NULL;
1133 }
1134 return pDomainConfiguration;
1135 }
1136
findConfiguration(const string & strConfiguration,string & strError) const1137 const CDomainConfiguration* CConfigurableDomain::findConfiguration(const string& strConfiguration, string& strError) const
1138 {
1139 const CDomainConfiguration* pDomainConfiguration = static_cast<const CDomainConfiguration*>(findChild(strConfiguration));
1140
1141 if (!pDomainConfiguration) {
1142
1143 strError = "Domain configuration " + strConfiguration + " not found";
1144
1145 return NULL;
1146 }
1147 return pDomainConfiguration;
1148 }
1149