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